summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKenneth Graunke <kenneth@whitecape.org>2014-01-24 10:47:49 -0800
committerCarl Worth <cworth@cworth.org>2014-01-25 16:55:24 -0800
commitfe2678accdd88df5126f5d7eae0be00cd9dd2e4d (patch)
tree887d6aa59c50aa3b0b290064e950f15f4eacf00a /src
parent83e9eb81be05d018cf04bfada0f4005145c9f7b8 (diff)
glsl: Fix chained assignments of vector channels.
Simple shaders such as: void splat(vec2 v, float f) { v[0] = v[1] = f; } failed to compile with the following error: error: value of type vec2 cannot be assigned to variable of type float First, we would process v[1] = f, and transform: LHS: (expression float vector_extract (var_ref v) (constant int (1))) RHS: (var_ref f) into: LHS: (var_ref v) RHS: (expression vec2 vector_insert (var_ref v) (constant int (1)) (var_ref f)) Note that the LHS type is now vec2, not a float. This is surprising, but not the real problem. After emitting assignments, this ultimately becomes: (declare (temporary) vec2 assignment_tmp) (assign (xy) (var_ref assignment_tmp) (expression vec2 vector_insert (var_ref v) (constant int (1)) (var_ref f))) (assign (xy) (var_ref v) (var_ref assignment_tmp)) We would then return (var_ref assignment_tmp) as the rvalue, which has the wrong type---it should be float, but is instead a vec2. To fix this, we simply return (vector_extract (var_ref assignment_temp) <the appropriate channel>) to pull out the desired float value. Fixes Piglit's chained-assignment-with-vector-constant-index.vert and chained-assignment-with-vector-dynamic-index.vert tests. Cc: mesa-stable@lists.freedesktop.org Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=74026 Reported-by: Dan Ginsburg <dang@valvesoftware.com> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Matt Turner <mattst88@gmail.com> Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> (cherry picked from commit 44a86e2b4fca7c7cab243dfa62dc17f4379fc8e3)
Diffstat (limited to 'src')
-rw-r--r--src/glsl/ast_to_hir.cpp20
1 files changed, 19 insertions, 1 deletions
diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
index a81a0518b27..9604c9b978a 100644
--- a/src/glsl/ast_to_hir.cpp
+++ b/src/glsl/ast_to_hir.cpp
@@ -734,6 +734,7 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
{
void *ctx = state;
bool error_emitted = (lhs->type->is_error() || rhs->type->is_error());
+ ir_rvalue *extract_channel = NULL;
/* If the assignment LHS comes back as an ir_binop_vector_extract
* expression, move it to the RHS as an ir_triop_vector_insert.
@@ -749,11 +750,23 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
if (new_rhs == NULL) {
return lhs;
} else {
+ /* This converts:
+ * - LHS: (expression float vector_extract <vec> <channel>)
+ * - RHS: <scalar>
+ * into:
+ * - LHS: <vec>
+ * - RHS: (expression vec2 vector_insert <vec> <channel> <scalar>)
+ *
+ * The LHS type is now a vector instead of a scalar. Since GLSL
+ * allows assignments to be used as rvalues, we need to re-extract
+ * the channel from assignment_temp when returning the rvalue.
+ */
+ extract_channel = lhs_expr->operands[1];
rhs = new(ctx) ir_expression(ir_triop_vector_insert,
lhs_expr->operands[0]->type,
lhs_expr->operands[0],
new_rhs,
- lhs_expr->operands[1]);
+ extract_channel);
lhs = lhs_expr->operands[0]->clone(ctx, NULL);
}
}
@@ -848,6 +861,11 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
if (!error_emitted)
instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var));
+ if (extract_channel) {
+ return new(ctx) ir_expression(ir_binop_vector_extract,
+ new(ctx) ir_dereference_variable(var),
+ extract_channel->clone(ctx, NULL));
+ }
return new(ctx) ir_dereference_variable(var);
}