On 31 October 2011 18:07, Ian Romanick <span dir="ltr"><<a href="mailto:idr@freedesktop.org">idr@freedesktop.org</a>></span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
From: Ian Romanick <<a href="mailto:ian.d.romanick@intel.com">ian.d.romanick@intel.com</a>><br>
<br>
This requires tracking a couple extra fields in ir_variable:<br>
<br>
* A flag to indicate that a variable had an initializer.<br>
<br>
* For non-const variables, a field to track the constant value of the<br>
variable's initializer.<br>
<br>
For variables non-constant initalizers, ir_variable::has_initializer<br>
will be true, but ir_variable::constant_initializer will be NULL. The<br>
linker can use the values of these fields to check adherence to the<br>
GLSL 4.20 rules for shared global variables:<br>
<br>
"If a shared global has multiple initializers, the initializers<br>
must all be constant expressions, and they must all have the same<br>
value. Otherwise, a link error will result. (A shared global<br>
having only one initializer does not require that initializer to<br>
be a constant expression.)"<br>
<br>
Previous to 4.20 the GLSL spec simply said that initializers must have<br>
the same value. In this case of non-constant initializers, this was<br>
impossible to determine. As a result, no vendor actually implemented<br>
that behavior. The 4.20 behavior matches the behavior of NVIDIA's<br>
shipping implementations.<br>
<br>
NOTE: This is candidate for the 7.11 branch. This patch also needs<br>
the preceding patch "glsl: Refactor generate_ARB_draw_buffers_variables<br>
to use add_builtin_constant"<br>
<br>
Signed-off-by: Ian Romanick <<a href="mailto:ian.d.romanick@intel.com">ian.d.romanick@intel.com</a>><br>
Bugzilla: <a href="https://bugs.freedesktop.org/show_bug.cgi?id=34687" target="_blank">https://bugs.freedesktop.org/show_bug.cgi?id=34687</a><br></blockquote><div><br>I have a few concerns about this patch, which we talked about in person today. To summarize for the list:<br>
<br>- There's a "finishme" comment just above the last hunk that I think we should really address. The test "glsl-link-initializers-03" is trying to demonstrate that problem, but it has bugs. I'll submit an improved "glsl-link-initializers-03" to the list.<br>
<br>- I think these changes regress propagation of uniform initializers. In other words, if one shader initializes a uniform and the other doesn't, then depending on the order in which the shaders are linked, the initializer might be lost.<br>
<br>That said, this is clearly an improvement over the previous state of the code, and I would be ok with accepting the patches and then doing some follow-up fixes.<br> </div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
---<br>
src/glsl/ast_to_hir.cpp | 3 ++<br>
src/glsl/ir.cpp | 5 ++++<br>
src/glsl/ir.h | 18 +++++++++++++++++<br>
src/glsl/ir_clone.cpp | 5 ++++<br>
src/glsl/ir_validate.cpp | 7 ++++++<br>
src/glsl/ir_variable.cpp | 2 +<br>
src/glsl/linker.cpp | 48 +++++++++++++++++++++++++++++++++++++++------<br>
7 files changed, 81 insertions(+), 7 deletions(-)<br>
<br>
diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp<br>
index 7584fdf..bd9c33d 100644<br>
--- a/src/glsl/ast_to_hir.cpp<br>
+++ b/src/glsl/ast_to_hir.cpp<br>
@@ -2351,6 +2351,9 @@ process_initializer(ir_variable *var, ast_declaration *decl,<br>
} else<br>
initializer_type = rhs->type;<br>
<br>
+ var->constant_initializer = rhs->constant_expression_value();<br>
+ var->has_initializer = true;<br>
+<br>
/* If the declared variable is an unsized array, it must inherrit<br>
* its full type from the initializer. A declaration such as<br>
*<br>
diff --git a/src/glsl/ir.cpp b/src/glsl/ir.cpp<br>
index ef7300e..a5eca5a 100644<br>
--- a/src/glsl/ir.cpp<br>
+++ b/src/glsl/ir.cpp<br>
@@ -1326,9 +1326,11 @@ ir_variable::ir_variable(const struct glsl_type *type, const char *name,<br>
this->type = type;<br>
this->name = ralloc_strdup(this, name);<br>
this->explicit_location = false;<br>
+ this->has_initializer = false;<br>
this->location = -1;<br>
this->warn_extension = NULL;<br>
this->constant_value = NULL;<br>
+ this->constant_initializer = NULL;<br>
this->origin_upper_left = false;<br>
this->pixel_center_integer = false;<br>
this->depth_layout = ir_depth_layout_none;<br>
@@ -1489,6 +1491,9 @@ steal_memory(ir_instruction *ir, void *new_ctx)<br>
if (var != NULL && var->constant_value != NULL)<br>
steal_memory(var->constant_value, ir);<br>
<br>
+ if (var != NULL && var->constant_initializer != NULL)<br>
+ steal_memory(var->constant_initializer, ir);<br>
+<br>
/* The components of aggregate constants are not visited by the normal<br>
* visitor, so steal their values by hand.<br>
*/<br>
diff --git a/src/glsl/ir.h b/src/glsl/ir.h<br>
index abbf455..5878c05 100644<br>
--- a/src/glsl/ir.h<br>
+++ b/src/glsl/ir.h<br>
@@ -365,6 +365,14 @@ public:<br>
unsigned explicit_location:1;<br>
<br>
/**<br>
+ * Does this variable have an initializer?<br>
+ *<br>
+ * This is used by the linker to cross-validiate initializers of global<br>
+ * variables.<br>
+ */<br>
+ unsigned has_initializer:1;<br>
+<br>
+ /**<br>
* \brief Layout qualifier for gl_FragDepth.<br>
*<br>
* This is not equal to \c ir_depth_layout_none if and only if this<br>
@@ -414,6 +422,16 @@ public:<br>
* Value assigned in the initializer of a variable declared "const"<br>
*/<br>
ir_constant *constant_value;<br>
+<br>
+ /**<br>
+ * Constant expression assigned in the initializer of the variable<br>
+ *<br>
+ * \warning<br>
+ * This field and \c ::constant_value are distinct. Even if the two fields<br>
+ * refer to constants with the same value, they must point to separate<br>
+ * objects.<br>
+ */<br>
+ ir_constant *constant_initializer;<br>
};<br>
<br>
<br>
diff --git a/src/glsl/ir_clone.cpp b/src/glsl/ir_clone.cpp<br>
index 9adf470..e8ac9fb 100644<br>
--- a/src/glsl/ir_clone.cpp<br>
+++ b/src/glsl/ir_clone.cpp<br>
@@ -50,6 +50,7 @@ ir_variable::clone(void *mem_ctx, struct hash_table *ht) const<br>
var->origin_upper_left = this->origin_upper_left;<br>
var->pixel_center_integer = this->pixel_center_integer;<br>
var->explicit_location = this->explicit_location;<br>
+ var->has_initializer = this->has_initializer;<br>
<br>
var->num_state_slots = this->num_state_slots;<br>
if (this->state_slots) {<br>
@@ -68,6 +69,10 @@ ir_variable::clone(void *mem_ctx, struct hash_table *ht) const<br>
if (this->constant_value)<br>
var->constant_value = this->constant_value->clone(mem_ctx, ht);<br>
<br>
+ if (this->constant_initializer)<br>
+ var->constant_initializer =<br>
+ this->constant_initializer->clone(mem_ctx, ht);<br>
+<br>
if (ht) {<br>
hash_table_insert(ht, var, (void *)const_cast<ir_variable *>(this));<br>
}<br>
diff --git a/src/glsl/ir_validate.cpp b/src/glsl/ir_validate.cpp<br>
index c387ecb..a352012 100644<br>
--- a/src/glsl/ir_validate.cpp<br>
+++ b/src/glsl/ir_validate.cpp<br>
@@ -496,6 +496,13 @@ ir_validate::visit(ir_variable *ir)<br>
}<br>
}<br>
<br>
+ if (ir->constant_initializer != NULL && !ir->has_initializer) {<br>
+ printf("ir_variable didn't have an initializer, but has a constant "<br>
+ "initializer value.\n");<br>
+ ir->print();<br>
+ abort();<br>
+ }<br>
+<br>
return visit_continue;<br>
}<br>
<br>
diff --git a/src/glsl/ir_variable.cpp b/src/glsl/ir_variable.cpp<br>
index bea0b2b..e719abe 100644<br>
--- a/src/glsl/ir_variable.cpp<br>
+++ b/src/glsl/ir_variable.cpp<br>
@@ -408,6 +408,8 @@ add_builtin_constant(exec_list *instructions, glsl_symbol_table *symtab,<br>
name, glsl_type::int_type,<br>
ir_var_auto, -1);<br>
var->constant_value = new(var) ir_constant(value);<br>
+ var->constant_initializer = new(var) ir_constant(value);<br>
+ var->has_initializer = true;<br>
return var;<br>
}<br>
<br>
diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp<br>
index a595c9c..915d5bb 100644<br>
--- a/src/glsl/linker.cpp<br>
+++ b/src/glsl/linker.cpp<br>
@@ -448,17 +448,30 @@ cross_validate_globals(struct gl_shader_program *prog,<br>
}<br>
}<br>
<br>
- /* FINISHME: Handle non-constant initializers.<br>
+ /* Page 35 (page 41 of the PDF) of the GLSL 4.20 spec says:<br>
+ *<br>
+ * "If a shared global has multiple initializers, the<br>
+ * initializers must all be constant expressions, and they<br>
+ * must all have the same value. Otherwise, a link error will<br>
+ * result. (A shared global having only one initializer does<br>
+ * not require that initializer to be a constant expression.)"<br>
+ *<br>
+ * Previous to 4.20 the GLSL spec simply said that initializers<br>
+ * must have the same value. In this case of non-constant<br>
+ * initializers, this was impossible to determine. As a result,<br>
+ * no vendor actually implemented that behavior. The 4.20<br>
+ * behavior matches the implemented behavior of at least one other<br>
+ * vendor, so we'll implement that for all GLSL versions.<br>
*/<br>
- if (var->constant_value != NULL) {<br>
- if (existing->constant_value != NULL) {<br>
- if (!var->constant_value->has_value(existing->constant_value)) {<br>
+ if (var->constant_initializer != NULL) {<br>
+ if (existing->constant_initializer != NULL) {<br>
+ if (!var->constant_initializer->has_value(existing->constant_initializer)) {<br>
linker_error(prog, "initializers for %s "<br>
"`%s' have differing values\n",<br>
mode_string(var), var->name);<br>
return false;<br>
}<br>
- } else<br>
+ } else {<br>
/* If the first-seen instance of a particular uniform did not<br>
* have an initializer but a later instance does, copy the<br>
* initializer to the version stored in the symbol table.<br>
@@ -471,8 +484,29 @@ cross_validate_globals(struct gl_shader_program *prog,<br>
* FINISHME: modify the shader, and linking with the second<br>
* FINISHME: will fail.<br>
*/<br>
- existing->constant_value =<br>
- var->constant_value->clone(ralloc_parent(existing), NULL);<br>
+ existing->constant_initializer =<br>
+ var->constant_initializer->clone(ralloc_parent(existing),<br>
+ NULL);<br>
+ }<br>
+ }<br>
+<br>
+ if (var->has_initializer) {<br>
+ if (existing->has_initializer<br>
+ && (var->constant_initializer == NULL<br>
+ || existing->constant_initializer == NULL)) {<br>
+ linker_error(prog,<br>
+ "shared global variable `%s' has multiple "<br>
+ "non-constant initializers.\n",<br>
+ var->name);<br>
+ return false;<br>
+ }<br>
+<br>
+ /* Some instance had an initializer, so keep track of that. In<br>
+ * this location, all sorts of initializers (constant or<br>
+ * otherwise) will propagate the existence to the variable<br>
+ * stored in the symbol table.<br>
+ */<br>
+ existing->has_initializer = true;<br>
}<br>
<br>
if (existing->invariant != var->invariant) {<br>
<font color="#888888">--<br>
1.7.6.4<br>
<br>
_______________________________________________<br>
mesa-dev mailing list<br>
<a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/mesa-dev" target="_blank">http://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
</font></blockquote></div><br>