summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Romanick <ian.d.romanick@intel.com>2010-06-18 17:13:42 -0700
committerIan Romanick <ian.d.romanick@intel.com>2010-06-23 10:56:03 -0700
commitcc22c5a5447d1d710e49524ee61b76268c7da6b9 (patch)
treea8af64aa7f652b443a50cad494af42a5d0877222
parent1e8b7a714e8acbb5028a250048452f2efc29d02e (diff)
linker: Initial implementation of interstage uniform validation
-rw-r--r--linker.cpp70
1 files changed, 69 insertions, 1 deletions
diff --git a/linker.cpp b/linker.cpp
index 0a1afcf..a7eff55 100644
--- a/linker.cpp
+++ b/linker.cpp
@@ -170,6 +170,60 @@ validate_fragment_shader_executable(struct glsl_shader *shader)
}
+/**
+ * Perform validation of uniforms used across multiple shader stages
+ */
+bool
+cross_validate_uniforms(struct glsl_shader **shaders, unsigned num_shaders)
+{
+ /* Examine all of the uniforms in all of the shaders and cross validate
+ * them.
+ */
+ glsl_symbol_table uniforms;
+ for (unsigned i = 0; i < num_shaders; i++) {
+ foreach_list(node, &shaders[i]->ir) {
+ ir_variable *const var = ((ir_instruction *) node)->as_variable();
+
+ if ((var == NULL) || (var->mode != ir_var_uniform))
+ continue;
+
+ /* If a uniform with this name has already been seen, verify that the
+ * new instance has the same type. In addition, if the uniforms have
+ * initializers, the values of the initializers must be the same.
+ */
+ ir_variable *const existing = uniforms.get_variable(var->name);
+ if (existing != NULL) {
+ if (var->type != existing->type) {
+ printf("error: uniform `%s' declared as type `%s' and "
+ "type `%s'\n",
+ var->name, var->type->name, existing->type->name);
+ return false;
+ }
+
+ if (var->constant_value != NULL) {
+ if (existing->constant_value != NULL) {
+ if (!var->constant_value->has_value(existing->constant_value)) {
+ printf("error: initializers for uniform `%s' have "
+ "differing values\n",
+ var->name);
+ return false;
+ }
+ } else
+ /* If the first-seen instance of a particular uniform did not
+ * have an initializer but a later instance does, copy the
+ * initializer to the version stored in the symbol table.
+ */
+ existing->constant_value = var->constant_value->clone();
+ }
+ } else
+ uniforms.add_variable(var->name, var);
+ }
+ }
+
+ return true;
+}
+
+
void
link_shaders(struct glsl_program *prog)
{
@@ -217,8 +271,22 @@ link_shaders(struct glsl_program *prog)
/* FINISHME: Perform inter-stage linking. */
+ glsl_shader *shader_executables[2];
+ unsigned num_shader_executables;
+
+ num_shader_executables = 0;
+ if (num_vert_shaders > 0) {
+ shader_executables[num_shader_executables] = vert_shader_list[0];
+ num_shader_executables++;
+ }
+
+ if (num_frag_shaders > 0) {
+ shader_executables[num_shader_executables] = frag_shader_list[0];
+ num_shader_executables++;
+ }
- prog->LinkStatus = true;
+ if (cross_validate_uniforms(shader_executables, num_shader_executables))
+ prog->LinkStatus = true;
done:
free(vert_shader_list);