diff options
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r-- | mesalib/src/glsl/glsl_parser.yy | 10 | ||||
-rw-r--r-- | mesalib/src/glsl/ir_clone.cpp | 2 | ||||
-rw-r--r-- | mesalib/src/glsl/link_functions.cpp | 32 | ||||
-rw-r--r-- | mesalib/src/glsl/link_varyings.cpp | 225 | ||||
-rw-r--r-- | mesalib/src/glsl/link_varyings.h | 3 |
5 files changed, 182 insertions, 90 deletions
diff --git a/mesalib/src/glsl/glsl_parser.yy b/mesalib/src/glsl/glsl_parser.yy index d8e589d49..fa6e2053a 100644 --- a/mesalib/src/glsl/glsl_parser.yy +++ b/mesalib/src/glsl/glsl_parser.yy @@ -1714,13 +1714,17 @@ struct_declaration_list: ; struct_declaration: - type_specifier struct_declarator_list ';' + fully_specified_type struct_declarator_list ';' { void *ctx = state; - ast_fully_specified_type *type = new(ctx) ast_fully_specified_type(); + ast_fully_specified_type *const type = $1; type->set_location(yylloc); - type->specifier = $1; + if (type->qualifier.flags.i != 0) + _mesa_glsl_error(&@1, state, + "only precision qualifiers may be applied to " + "structure members"); + $$ = new(ctx) ast_declarator_list(type); $$->set_location(yylloc); diff --git a/mesalib/src/glsl/ir_clone.cpp b/mesalib/src/glsl/ir_clone.cpp index 9d4178de8..a75b3b762 100644 --- a/mesalib/src/glsl/ir_clone.cpp +++ b/mesalib/src/glsl/ir_clone.cpp @@ -59,6 +59,8 @@ ir_variable::clone(void *mem_ctx, struct hash_table *ht) const var->explicit_binding = this->explicit_binding; var->has_initializer = this->has_initializer; var->depth_layout = this->depth_layout; + var->assigned = this->assigned; + var->used = this->used; var->num_state_slots = this->num_state_slots; if (this->state_slots) { diff --git a/mesalib/src/glsl/link_functions.cpp b/mesalib/src/glsl/link_functions.cpp index 6b3e15448..dd6f24716 100644 --- a/mesalib/src/glsl/link_functions.cpp +++ b/mesalib/src/glsl/link_functions.cpp @@ -173,6 +173,38 @@ public: return visit_continue; } + virtual ir_visitor_status visit_leave(ir_call *ir) + { + /* Traverse list of function parameters, and for array parameters + * propagate max_array_access. Otherwise arrays that are only referenced + * from inside functions via function parameters will be incorrectly + * optimized. This will lead to incorrect code being generated (or worse). + * Do it when leaving the node so the children would propagate their + * array accesses first. + */ + + const exec_node *formal_param_node = ir->callee->parameters.get_head(); + if (formal_param_node) { + const exec_node *actual_param_node = ir->actual_parameters.get_head(); + while (!actual_param_node->is_tail_sentinel()) { + ir_variable *formal_param = (ir_variable *) formal_param_node; + ir_rvalue *actual_param = (ir_rvalue *) actual_param_node; + + formal_param_node = formal_param_node->get_next(); + actual_param_node = actual_param_node->get_next(); + + if (formal_param->type->is_array()) { + ir_dereference_variable *deref = actual_param->as_dereference_variable(); + if (deref && deref->var && deref->var->type->is_array()) { + deref->var->max_array_access = + MAX2(formal_param->max_array_access, deref->var->max_array_access); + } + } + } + } + return visit_continue; + } + virtual ir_visitor_status visit(ir_dereference_variable *ir) { if (hash_table_find(locals, ir->var) == NULL) { diff --git a/mesalib/src/glsl/link_varyings.cpp b/mesalib/src/glsl/link_varyings.cpp index 4ceb1d33e..081a51da5 100644 --- a/mesalib/src/glsl/link_varyings.cpp +++ b/mesalib/src/glsl/link_varyings.cpp @@ -41,6 +41,118 @@ /** + * Validate the types and qualifiers of an output from one stage against the + * matching input to another stage. + */ +static void +cross_validate_types_and_qualifiers(struct gl_shader_program *prog, + const ir_variable *input, + const ir_variable *output, + GLenum consumer_type, + GLenum producer_type) +{ + /* Check that the types match between stages. + */ + const glsl_type *type_to_match = input->type; + if (consumer_type == GL_GEOMETRY_SHADER) { + assert(type_to_match->is_array()); /* Enforced by ast_to_hir */ + type_to_match = type_to_match->element_type(); + } + if (type_to_match != output->type) { + /* There is a bit of a special case for gl_TexCoord. This + * built-in is unsized by default. Applications that variable + * access it must redeclare it with a size. There is some + * language in the GLSL spec that implies the fragment shader + * and vertex shader do not have to agree on this size. Other + * driver behave this way, and one or two applications seem to + * rely on it. + * + * Neither declaration needs to be modified here because the array + * sizes are fixed later when update_array_sizes is called. + * + * From page 48 (page 54 of the PDF) of the GLSL 1.10 spec: + * + * "Unlike user-defined varying variables, the built-in + * varying variables don't have a strict one-to-one + * correspondence between the vertex language and the + * fragment language." + */ + if (!output->type->is_array() + || (strncmp("gl_", output->name, 3) != 0)) { + linker_error(prog, + "%s shader output `%s' declared as type `%s', " + "but %s shader input declared as type `%s'\n", + _mesa_glsl_shader_target_name(producer_type), + output->name, + output->type->name, + _mesa_glsl_shader_target_name(consumer_type), + input->type->name); + return; + } + } + + /* Check that all of the qualifiers match between stages. + */ + if (input->centroid != output->centroid) { + linker_error(prog, + "%s shader output `%s' %s centroid qualifier, " + "but %s shader input %s centroid qualifier\n", + _mesa_glsl_shader_target_name(producer_type), + output->name, + (output->centroid) ? "has" : "lacks", + _mesa_glsl_shader_target_name(consumer_type), + (input->centroid) ? "has" : "lacks"); + return; + } + + if (input->invariant != output->invariant) { + linker_error(prog, + "%s shader output `%s' %s invariant qualifier, " + "but %s shader input %s invariant qualifier\n", + _mesa_glsl_shader_target_name(producer_type), + output->name, + (output->invariant) ? "has" : "lacks", + _mesa_glsl_shader_target_name(consumer_type), + (input->invariant) ? "has" : "lacks"); + return; + } + + if (input->interpolation != output->interpolation) { + linker_error(prog, + "%s shader output `%s' specifies %s " + "interpolation qualifier, " + "but %s shader input specifies %s " + "interpolation qualifier\n", + _mesa_glsl_shader_target_name(producer_type), + output->name, + output->interpolation_string(), + _mesa_glsl_shader_target_name(consumer_type), + input->interpolation_string()); + return; + } +} + +/** + * Validate front and back color outputs against single color input + */ +static void +cross_validate_front_and_back_color(struct gl_shader_program *prog, + const ir_variable *input, + const ir_variable *front_color, + const ir_variable *back_color, + GLenum consumer_type, + GLenum producer_type) +{ + if (front_color != NULL && front_color->assigned) + cross_validate_types_and_qualifiers(prog, input, front_color, + consumer_type, producer_type); + + if (back_color != NULL && back_color->assigned) + cross_validate_types_and_qualifiers(prog, input, back_color, + consumer_type, producer_type); +} + +/** * Validate that outputs from one stage match inputs of another */ void @@ -48,10 +160,6 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog, gl_shader *producer, gl_shader *consumer) { glsl_symbol_table parameters; - const char *const producer_stage = - _mesa_glsl_shader_target_name(producer->Type); - const char *const consumer_stage = - _mesa_glsl_shader_target_name(consumer->Type); /* Find all shader outputs in the "producer" stage. */ @@ -79,85 +187,32 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog, if ((input == NULL) || (input->mode != ir_var_shader_in)) continue; - ir_variable *const output = parameters.get_variable(input->name); - if (output != NULL) { - /* Check that the types match between stages. - */ - const glsl_type *type_to_match = input->type; - if (consumer->Type == GL_GEOMETRY_SHADER) { - assert(type_to_match->is_array()); /* Enforced by ast_to_hir */ - type_to_match = type_to_match->element_type(); + if (strcmp(input->name, "gl_Color") == 0 && input->used) { + const ir_variable *const front_color = + parameters.get_variable("gl_FrontColor"); + + const ir_variable *const back_color = + parameters.get_variable("gl_BackColor"); + + cross_validate_front_and_back_color(prog, input, + front_color, back_color, + consumer->Type, producer->Type); + } else if (strcmp(input->name, "gl_SecondaryColor") == 0 && input->used) { + const ir_variable *const front_color = + parameters.get_variable("gl_FrontSecondaryColor"); + + const ir_variable *const back_color = + parameters.get_variable("gl_BackSecondaryColor"); + + cross_validate_front_and_back_color(prog, input, + front_color, back_color, + consumer->Type, producer->Type); + } else { + ir_variable *const output = parameters.get_variable(input->name); + if (output != NULL) { + cross_validate_types_and_qualifiers(prog, input, output, + consumer->Type, producer->Type); } - if (type_to_match != output->type) { - /* There is a bit of a special case for gl_TexCoord. This - * built-in is unsized by default. Applications that variable - * access it must redeclare it with a size. There is some - * language in the GLSL spec that implies the fragment shader - * and vertex shader do not have to agree on this size. Other - * driver behave this way, and one or two applications seem to - * rely on it. - * - * Neither declaration needs to be modified here because the array - * sizes are fixed later when update_array_sizes is called. - * - * From page 48 (page 54 of the PDF) of the GLSL 1.10 spec: - * - * "Unlike user-defined varying variables, the built-in - * varying variables don't have a strict one-to-one - * correspondence between the vertex language and the - * fragment language." - */ - if (!output->type->is_array() - || (strncmp("gl_", output->name, 3) != 0)) { - linker_error(prog, - "%s shader output `%s' declared as type `%s', " - "but %s shader input declared as type `%s'\n", - producer_stage, output->name, - output->type->name, - consumer_stage, input->type->name); - return; - } - } - - /* Check that all of the qualifiers match between stages. - */ - if (input->centroid != output->centroid) { - linker_error(prog, - "%s shader output `%s' %s centroid qualifier, " - "but %s shader input %s centroid qualifier\n", - producer_stage, - output->name, - (output->centroid) ? "has" : "lacks", - consumer_stage, - (input->centroid) ? "has" : "lacks"); - return; - } - - if (input->invariant != output->invariant) { - linker_error(prog, - "%s shader output `%s' %s invariant qualifier, " - "but %s shader input %s invariant qualifier\n", - producer_stage, - output->name, - (output->invariant) ? "has" : "lacks", - consumer_stage, - (input->invariant) ? "has" : "lacks"); - return; - } - - if (input->interpolation != output->interpolation) { - linker_error(prog, - "%s shader output `%s' specifies %s " - "interpolation qualifier, " - "but %s shader input specifies %s " - "interpolation qualifier\n", - producer_stage, - output->name, - output->interpolation_string(), - consumer_stage, - input->interpolation_string()); - return; - } } } } @@ -172,8 +227,8 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog, * will fail to find any matching variable. */ void -tfeedback_decl::init(struct gl_context *ctx, struct gl_shader_program *prog, - const void *mem_ctx, const char *input) +tfeedback_decl::init(struct gl_context *ctx, const void *mem_ctx, + const char *input) { /* We don't have to be pedantic about what is a valid GLSL variable name, * because any variable with an invalid name can't exist in the IR anyway. @@ -443,7 +498,7 @@ parse_tfeedback_decls(struct gl_context *ctx, struct gl_shader_program *prog, char **varying_names, tfeedback_decl *decls) { for (unsigned i = 0; i < num_names; ++i) { - decls[i].init(ctx, prog, mem_ctx, varying_names[i]); + decls[i].init(ctx, mem_ctx, varying_names[i]); if (!decls[i].is_varying()) continue; diff --git a/mesalib/src/glsl/link_varyings.h b/mesalib/src/glsl/link_varyings.h index 302ab5c26..6264ef05b 100644 --- a/mesalib/src/glsl/link_varyings.h +++ b/mesalib/src/glsl/link_varyings.h @@ -91,8 +91,7 @@ struct tfeedback_candidate class tfeedback_decl { public: - void init(struct gl_context *ctx, struct gl_shader_program *prog, - const void *mem_ctx, const char *input); + void init(struct gl_context *ctx, const void *mem_ctx, const char *input); static bool is_same(const tfeedback_decl &x, const tfeedback_decl &y); bool assign_location(struct gl_context *ctx, struct gl_shader_program *prog); |