glsl2: Write vector constructor constants in a single assignment

Make two passes over the constructor parameters.  Write all of the
constants in a single write, then write the non-constants one at a
time.  This causes the fragment shader

varying float g;
void main()
{
	gl_FragColor = vec4(0.0, g, 0.0, 1.0);
}

to generate

(function main
  (signature void (parameters )
    (
      (declare (temporary ) vec4 vec_ctor@0x8580058)
      (assign (constant bool (1)) (xzw) (var_ref vec_ctor@0x8580058)  (constant vec4 (0.000000 0.000000 0.000000 1.000000)) )
      (assign (constant bool (1)) (y) (var_ref vec_ctor@0x8580058)  (swiz xxxx (var_ref g@0x8580218) ))
      (assign (constant bool (1)) (xyzw) (var_ref gl_FragColor@0x84d32a0)  (var_ref vec_ctor@0x8580058) )
    ))
)

instead of

(function main
  (signature void (parameters )
    (
      (declare (temporary ) vec4 vec_ctor@0x8580058)
      (assign (constant bool (1)) (x) (var_ref vec_ctor@0x8580058)  (constant vec4 (0.000000 0.000000 0.000000 1.000000)) )
      (assign (constant bool (1)) (y) (var_ref vec_ctor@0x8580058)  (swiz xxxx (var_ref g@0x8580218) ))
      (assign (constant bool (1)) (z) (var_ref vec_ctor@0x8580058)  (constant vec4 (0.000000 0.000000 0.000000 1.000000)) )
      (assign (constant bool (1)) (w) (var_ref vec_ctor@0x8580058)  (constant vec4 (0.000000 0.000000 0.000000 1.000000)) )
      (assign (constant bool (1)) (xyzw) (var_ref gl_FragColor@0x84d32a0)  (var_ref vec_ctor@0x8580058) )
    ))
)

A similar optimization could be done for matrix constructors, but it
is a little more complicate there.
This commit is contained in:
Ian Romanick 2010-08-31 14:44:13 -07:00
parent 99f3c9caa3
commit a6c3cd5ca6
1 changed files with 73 additions and 12 deletions

View File

@ -621,6 +621,11 @@ emit_inline_vector_constructor(const glsl_type *type,
instructions->push_tail(inst);
} else {
unsigned base_component = 0;
ir_constant_data data;
unsigned constant_mask = 0;
memset(&data, 0, sizeof(data));
foreach_list(node, parameters) {
ir_rvalue *param = (ir_rvalue *) node;
unsigned rhs_components = param->type->components();
@ -631,24 +636,80 @@ emit_inline_vector_constructor(const glsl_type *type,
rhs_components = lhs_components - base_component;
}
/* Generate a swizzle that puts the first element of the source at
* the location of the first element of the destination.
*/
unsigned swiz[4] = { 0, 0, 0, 0 };
for (unsigned i = 0; i < rhs_components; i++)
swiz[i + base_component] = i;
const ir_constant *const c = param->as_constant();
if (c != NULL) {
for (unsigned i = 0; i < rhs_components; i++) {
switch (c->type->base_type) {
case GLSL_TYPE_UINT:
data.u[i + base_component] = c->get_uint_component(i);
break;
case GLSL_TYPE_INT:
data.i[i + base_component] = c->get_int_component(i);
break;
case GLSL_TYPE_FLOAT:
data.f[i + base_component] = c->get_float_component(i);
break;
case GLSL_TYPE_BOOL:
data.b[i + base_component] = c->get_bool_component(i);
break;
default:
assert(!"Should not get here.");
break;
}
}
/* Mask of fields to be written in the assignment.
*/
const unsigned write_mask = ((1U << rhs_components) - 1)
<< base_component;
/* Mask of fields to be written in the assignment.
*/
constant_mask |= ((1U << rhs_components) - 1) << base_component;
}
/* Advance the component index by the number of components that were
* just assigned.
*/
base_component += rhs_components;
}
if (constant_mask != 0) {
ir_dereference *lhs = new(ctx) ir_dereference_variable(var);
ir_rvalue *rhs = new(ctx) ir_swizzle(param, swiz, lhs_components);
ir_rvalue *rhs = new(ctx) ir_constant(var->type, &data);
ir_instruction *inst =
new(ctx) ir_assignment(lhs, rhs, NULL, write_mask);
new(ctx) ir_assignment(lhs, rhs, NULL, constant_mask);
instructions->push_tail(inst);
}
base_component = 0;
foreach_list(node, parameters) {
ir_rvalue *param = (ir_rvalue *) node;
unsigned rhs_components = param->type->components();
/* Do not try to assign more components to the vector than it has!
*/
if ((rhs_components + base_component) > lhs_components) {
rhs_components = lhs_components - base_component;
}
const ir_constant *const c = param->as_constant();
if (c == NULL) {
/* Generate a swizzle that puts the first element of the source at
* the location of the first element of the destination.
*/
unsigned swiz[4] = { 0, 0, 0, 0 };
for (unsigned i = 0; i < rhs_components; i++)
swiz[i + base_component] = i;
/* Mask of fields to be written in the assignment.
*/
const unsigned write_mask = ((1U << rhs_components) - 1)
<< base_component;
ir_dereference *lhs = new(ctx) ir_dereference_variable(var);
ir_rvalue *rhs = new(ctx) ir_swizzle(param, swiz, lhs_components);
ir_instruction *inst =
new(ctx) ir_assignment(lhs, rhs, NULL, write_mask);
instructions->push_tail(inst);
}
/* Advance the component index by the number of components that were
* just assigned.