aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/glsl
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r--mesalib/src/glsl/glsl_parser.yy10
-rw-r--r--mesalib/src/glsl/ir_clone.cpp2
-rw-r--r--mesalib/src/glsl/link_functions.cpp32
-rw-r--r--mesalib/src/glsl/link_varyings.cpp225
-rw-r--r--mesalib/src/glsl/link_varyings.h3
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);