summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnuj Phogat <anuj.phogat@gmail.com>2014-05-01 15:43:17 -0700
committerCarl Worth <cworth@cworth.org>2014-05-05 11:23:20 -0700
commit2cd8ce4c67b1966f1957e2710cd87b92d38d3122 (patch)
tree97989bd84973fb482ef42f1d6e3bb6d2a0341aaf
parentec70be5628b0941767964cff6135b5ba0bf20766 (diff)
glsl: Link error if fs defines conflicting qualifiers for gl_FragCoord
GLSL 1.50 spec says: "If gl_FragCoord is redeclared in any fragment shader in a program, it must be redeclared in all the fragment shaders in that program that have a static use gl_FragCoord. All redeclarations of gl_FragCoord in all fragment shaders in a single program must have the same set of qualifiers." This patch causes the shader link to fail if we have multiple fragment shaders with conflicting layout qualifiers for gl_FragCoord. V2: Restructure the code and add conditions to correctly handle the following case: fragment shader 1: layout(origin_upper_left) in vec4 gl_FragCoord; void main() { foo(); gl_FragColor = gl_FragData; } fragment shader 2: layout(pixel_center_integer) in vec4 gl_FragCoord; void foo() { } V3: Allow linking in the following case: fragment shader 1: void main() { foo(); gl_FragColor = gl_FragCoord; } fragment shader 2: in vec4 gl_FragCoord; void foo() { ... } Signed-off-by: Anuj Phogat <anuj.phogat@gmail.com> Cc: <mesa-stable@lists.freedesktop.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> (cherry picked from commit 35f11e85cbe82b4bb77535e84e5515a5c49f67a6 with some manual backporting)
-rw-r--r--src/glsl/ast_to_hir.cpp5
-rw-r--r--src/glsl/glsl_parser_extras.cpp23
-rw-r--r--src/glsl/glsl_parser_extras.h1
-rw-r--r--src/glsl/linker.cpp77
-rw-r--r--src/mesa/main/mtypes.h8
5 files changed, 113 insertions, 1 deletions
diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
index c5996faaf75..1b97bc63052 100644
--- a/src/glsl/ast_to_hir.cpp
+++ b/src/glsl/ast_to_hir.cpp
@@ -119,6 +119,11 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
instructions->push_head(var);
}
+ /* Figure out if gl_FragCoord is actually used in fragment shader */
+ ir_variable *const var = state->symbols->get_variable("gl_FragCoord");
+ if (var != NULL)
+ state->fs_uses_gl_fragcoord = var->data.used;
+
/* From section 7.1 (Built-In Language Variables) of the GLSL 4.10 spec:
*
* If multiple shaders using members of a built-in block belonging to
diff --git a/src/glsl/glsl_parser_extras.cpp b/src/glsl/glsl_parser_extras.cpp
index 6b7760feb3a..ad718759763 100644
--- a/src/glsl/glsl_parser_extras.cpp
+++ b/src/glsl/glsl_parser_extras.cpp
@@ -186,6 +186,12 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx,
this->default_uniform_qualifier->flags.q.shared = 1;
this->default_uniform_qualifier->flags.q.column_major = 1;
+ this->fs_uses_gl_fragcoord = false;
+ this->fs_redeclares_gl_fragcoord = false;
+ this->fs_origin_upper_left = false;
+ this->fs_pixel_center_integer = false;
+ this->fs_redeclares_gl_fragcoord_with_no_layout_qualifiers = false;
+
this->gs_input_prim_type_specified = false;
this->gs_input_prim_type = GL_POINTS;
this->gs_input_size = 0;
@@ -1332,7 +1338,14 @@ set_shader_inout_layout(struct gl_shader *shader,
/* Should have been prevented by the parser. */
assert(!state->gs_input_prim_type_specified);
assert(!state->out_qualifier->flags.i);
- return;
+ }
+
+ if (shader->Stage != MESA_SHADER_FRAGMENT) {
+ /* Should have been prevented by the parser. */
+ assert(!state->fs_uses_gl_fragcoord);
+ assert(!state->fs_redeclares_gl_fragcoord);
+ assert(!state->fs_pixel_center_integer);
+ assert(!state->fs_origin_upper_left);
}
switch(shader->Stage) {
@@ -1353,6 +1366,14 @@ set_shader_inout_layout(struct gl_shader *shader,
shader->Geom.OutputType = PRIM_UNKNOWN;
}
break;
+
+ case MESA_SHADER_FRAGMENT:
+ shader->redeclares_gl_fragcoord = state->fs_redeclares_gl_fragcoord;
+ shader->uses_gl_fragcoord = state->fs_uses_gl_fragcoord;
+ shader->pixel_center_integer = state->fs_pixel_center_integer;
+ shader->origin_upper_left = state->fs_origin_upper_left;
+ break;
+
default:
/* Nothing to do. */
break;
diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h
index 82a83a5cc2a..69387d6e95d 100644
--- a/src/glsl/glsl_parser_extras.h
+++ b/src/glsl/glsl_parser_extras.h
@@ -374,6 +374,7 @@ struct _mesa_glsl_parse_state {
const struct gl_extensions *extensions;
bool uses_builtin_functions;
+ bool fs_uses_gl_fragcoord;
/**
* For geometry shaders, size of the most recently seen input declaration
diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp
index 578cc78a6f8..235f58684c9 100644
--- a/src/glsl/linker.cpp
+++ b/src/glsl/linker.cpp
@@ -1195,6 +1195,82 @@ private:
};
/**
+ * Performs the cross-validation of layout qualifiers specified in
+ * redeclaration of gl_FragCoord for the attached fragment shaders,
+ * and propagates them to the linked FS and linked shader program.
+ */
+static void
+link_fs_input_layout_qualifiers(struct gl_shader_program *prog,
+ struct gl_shader *linked_shader,
+ struct gl_shader **shader_list,
+ unsigned num_shaders)
+{
+ linked_shader->redeclares_gl_fragcoord = false;
+ linked_shader->uses_gl_fragcoord = false;
+ linked_shader->origin_upper_left = false;
+ linked_shader->pixel_center_integer = false;
+
+ if (linked_shader->Stage != MESA_SHADER_FRAGMENT || prog->Version < 150)
+ return;
+
+ for (unsigned i = 0; i < num_shaders; i++) {
+ struct gl_shader *shader = shader_list[i];
+ /* From the GLSL 1.50 spec, page 39:
+ *
+ * "If gl_FragCoord is redeclared in any fragment shader in a program,
+ * it must be redeclared in all the fragment shaders in that program
+ * that have a static use gl_FragCoord."
+ *
+ * Exclude the case when one of the 'linked_shader' or 'shader' redeclares
+ * gl_FragCoord with no layout qualifiers but the other one doesn't
+ * redeclare it. If we strictly follow GLSL 1.50 spec's language, it
+ * should be a link error. But, generating link error for this case will
+ * be a wrong behaviour which spec didn't intend to do and it could also
+ * break some applications.
+ */
+ if ((linked_shader->redeclares_gl_fragcoord
+ && !shader->redeclares_gl_fragcoord
+ && shader->uses_gl_fragcoord
+ && (linked_shader->origin_upper_left
+ || linked_shader->pixel_center_integer))
+ || (shader->redeclares_gl_fragcoord
+ && !linked_shader->redeclares_gl_fragcoord
+ && linked_shader->uses_gl_fragcoord
+ && (shader->origin_upper_left
+ || shader->pixel_center_integer))) {
+ linker_error(prog, "fragment shader defined with conflicting "
+ "layout qualifiers for gl_FragCoord\n");
+ }
+
+ /* From the GLSL 1.50 spec, page 39:
+ *
+ * "All redeclarations of gl_FragCoord in all fragment shaders in a
+ * single program must have the same set of qualifiers."
+ */
+ if (linked_shader->redeclares_gl_fragcoord && shader->redeclares_gl_fragcoord
+ && (shader->origin_upper_left != linked_shader->origin_upper_left
+ || shader->pixel_center_integer != linked_shader->pixel_center_integer)) {
+ linker_error(prog, "fragment shader defined with conflicting "
+ "layout qualifiers for gl_FragCoord\n");
+ }
+
+ /* Update the linked shader state.  Note that uses_gl_fragcoord should
+ * accumulate the results.  The other values should replace.  If there
+ * are multiple redeclarations, all the fields except uses_gl_fragcoord
+ * are already known to be the same.
+ */
+ if (shader->redeclares_gl_fragcoord || shader->uses_gl_fragcoord) {
+ linked_shader->redeclares_gl_fragcoord =
+ shader->redeclares_gl_fragcoord;
+ linked_shader->uses_gl_fragcoord = linked_shader->uses_gl_fragcoord
+ || shader->uses_gl_fragcoord;
+ linked_shader->origin_upper_left = shader->origin_upper_left;
+ linked_shader->pixel_center_integer = shader->pixel_center_integer;
+ }
+ }
+}
+
+/**
* Performs the cross-validation of geometry shader max_vertices and
* primitive type layout qualifiers for the attached geometry shaders,
* and propagates them to the linked GS and linked shader program.
@@ -1390,6 +1466,7 @@ link_intrastage_shaders(void *mem_ctx,
linked->NumUniformBlocks = num_uniform_blocks;
ralloc_steal(linked, linked->UniformBlocks);
+ link_fs_input_layout_qualifiers(prog, linked, shader_list, num_shaders);
link_gs_inout_layout_qualifiers(prog, linked, shader_list, num_shaders);
populate_symbol_table(linked);
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index d5159e0a6bc..9356c6cc87e 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -2395,6 +2395,14 @@ struct gl_shader
struct glsl_symbol_table *symbols;
bool uses_builtin_functions;
+ bool uses_gl_fragcoord;
+ bool redeclares_gl_fragcoord;
+
+ /**
+ * Fragment shader state from GLSL 1.50 layout qualifiers.
+ */
+ bool origin_upper_left;
+ bool pixel_center_integer;
/**
* Geometry shader state from GLSL 1.50 layout qualifiers.