diff options
author | Eric Anholt <[email protected]> | 2010-09-22 11:47:03 -0700 |
---|---|---|
committer | Eric Anholt <[email protected]> | 2010-09-22 13:09:51 -0700 |
commit | b39e6f33b60ef9bbaf81f320aaca6a440d8a6a8f (patch) | |
tree | c3547819e402b729d84a4847aed95b81ec09fdbf /src/glsl/ir.cpp | |
parent | 38da5c9cb636387539daaf5688c2a3badee32447 (diff) |
glsl: Rework assignments with write_masks to have LHS chan count match RHS.
It turns out that most people new to this IR are surprised when an
assignment to (say) 3 components on the LHS takes 4 components on the
RHS. It also makes for quite strange IR output:
(assign (constant bool (1)) (x) (var_ref color) (swiz x (var_ref v) ))
(assign (constant bool (1)) (y) (var_ref color) (swiz yy (var_ref v) ))
(assign (constant bool (1)) (z) (var_ref color) (swiz zzz (var_ref v) ))
But even worse, even we get it wrong, as shown by this line of our
current step(float, vec4):
(assign (constant bool (1)) (w)
(var_ref t)
(expression float b2f (expression bool >=
(swiz w (var_ref x))(var_ref edge))))
where we try to assign a float to the writemasked-out x channel and
don't supply anything for the actual w channel we're writing. Drivers
right now just get lucky since ir_to_mesa spams the float value across
all the source channels of a vec4.
Instead, the RHS will now have a number of components equal to the
number of components actually being written. Hopefully this confuses
everyone less, and it also makes codegen for a scalar target simpler.
Reviewed-by: Kenneth Graunke <[email protected]>
Reviewed-by: Ian Romanick <[email protected]>
Diffstat (limited to 'src/glsl/ir.cpp')
-rw-r--r-- | src/glsl/ir.cpp | 29 |
1 files changed, 28 insertions, 1 deletions
diff --git a/src/glsl/ir.cpp b/src/glsl/ir.cpp index 7cc55d40b78..5e2109ecc6e 100644 --- a/src/glsl/ir.cpp +++ b/src/glsl/ir.cpp @@ -55,6 +55,9 @@ update_rhs_swizzle(ir_swizzle_mask &m, unsigned from, unsigned to) void ir_assignment::set_lhs(ir_rvalue *lhs) { + void *mem_ctx = this; + bool swizzled = false; + while (lhs != NULL) { ir_swizzle *swiz = lhs->as_swizzle(); @@ -82,7 +85,21 @@ ir_assignment::set_lhs(ir_rvalue *lhs) this->write_mask = write_mask; lhs = swiz->val; - this->rhs = new(this) ir_swizzle(this->rhs, rhs_swiz); + this->rhs = new(mem_ctx) ir_swizzle(this->rhs, rhs_swiz); + swizzled = true; + } + + if (swizzled) { + /* Now, RHS channels line up with the LHS writemask. Collapse it + * to just the channels that will be written. + */ + ir_swizzle_mask rhs_swiz = { 0, 0, 0, 0, 0, 0 }; + int rhs_chan = 0; + for (int i = 0; i < 4; i++) { + if (write_mask & (1 << i)) + update_rhs_swizzle(rhs_swiz, i, rhs_chan++); + } + this->rhs = new(mem_ctx) ir_swizzle(this->rhs, rhs_swiz); } assert((lhs == NULL) || lhs->as_dereference()); @@ -122,6 +139,16 @@ ir_assignment::ir_assignment(ir_dereference *lhs, ir_rvalue *rhs, this->rhs = rhs; this->lhs = lhs; this->write_mask = write_mask; + + if (lhs->type->is_scalar() || lhs->type->is_vector()) { + int lhs_components = 0; + for (int i = 0; i < 4; i++) { + if (write_mask & (1 << i)) + lhs_components++; + } + + assert(lhs_components == this->rhs->type->vector_elements); + } } ir_assignment::ir_assignment(ir_rvalue *lhs, ir_rvalue *rhs, |