[Mesa-dev] [PATCH 2/7] glsl: Create an ir_builder helper for hand-generating IR.
Kenneth Graunke
kenneth at whitecape.org
Wed Mar 28 10:48:29 PDT 2012
On 03/26/2012 12:42 PM, Eric Anholt wrote:
> The C++ constructors with placement new, while functional, are
> extremely verbose, leading to generation of simple GLSL IR expressions
> like (a * b + c * d) expanding to many lines of code and using lots of
> temporary variables. By creating a new ir_builder.h that puts simple
> generators in our namespace and taking advantage of ralloc_parent(),
> we can generate much more compact code, at a minor runtime cost.
> ---
> src/glsl/Makefile.sources | 1 +
> src/glsl/ir_builder.cpp | 69 ++++++++++++++++++
> src/glsl/ir_builder.h | 36 ++++++++++
> src/mesa/main/ff_fragment_shader.cpp | 128 ++++++++++++----------------------
> 4 files changed, 152 insertions(+), 82 deletions(-)
> create mode 100644 src/glsl/ir_builder.cpp
> create mode 100644 src/glsl/ir_builder.h
>
> diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources
> index 06728da..4e3b074 100644
> --- a/src/glsl/Makefile.sources
> +++ b/src/glsl/Makefile.sources
> @@ -26,6 +26,7 @@ LIBGLSL_CXX_FILES := \
> glsl_symbol_table.cpp \
> hir_field_selection.cpp \
> ir_basic_block.cpp \
> + ir_builder.cpp \
> ir_clone.cpp \
> ir_constant_expression.cpp \
> ir.cpp \
> diff --git a/src/glsl/ir_builder.cpp b/src/glsl/ir_builder.cpp
> new file mode 100644
> index 0000000..039ee1b
> --- /dev/null
> +++ b/src/glsl/ir_builder.cpp
> @@ -0,0 +1,69 @@
> +/*
> + * Copyright © 2012 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + */
> +
> +#include "ir_builder.h"
> +
> +using namespace ir_builder;
> +
> +namespace ir_builder {
> +
> +ir_expression *
> +expr(ir_expression_operation op,
> + ir_instruction *a, ir_instruction *b)
> +{
> + void *mem_ctx = ralloc_parent(a);
> +
> + return new(mem_ctx) ir_expression(op, a->as_rvalue(), b->as_rvalue());
> +}
x.X
Please use ir_rvalue everywhere rather than ir_instruction. ir_rvalue
is the base class for all expression trees/values, while ir_instruction
is the base class for statements.
This also would make passing a non-rvalue a compile time error (no
matching signature) rather than a run-time crash.
Otherwise, this patch looks pretty awesome. I am a fan. :)
> +
> +ir_expression *add(ir_instruction *a, ir_instruction *b)
> +{
> + return expr(ir_binop_add, a, b);
> +}
> +
> +ir_expression *sub(ir_instruction *a, ir_instruction *b)
> +{
> + return expr(ir_binop_sub, a, b);
> +}
> +
> +ir_expression *mul(ir_instruction *a, ir_instruction *b)
> +{
> + return expr(ir_binop_mul, a, b);
> +}
> +
> +ir_expression *dot(ir_instruction *a, ir_instruction *b)
> +{
> + return expr(ir_binop_dot, a, b);
> +}
> +
> +ir_expression *
> +saturate(ir_instruction *a)
> +{
> + void *mem_ctx = ralloc_parent(a);
> +
> + return expr(ir_binop_max,
> + expr(ir_binop_min, a, new(mem_ctx) ir_constant(1.0f)),
> + new(mem_ctx) ir_constant(0.0f));
> +}
> +
> +} /* namespace ir_builder */
> diff --git a/src/glsl/ir_builder.h b/src/glsl/ir_builder.h
> new file mode 100644
> index 0000000..5a26bb6
> --- /dev/null
> +++ b/src/glsl/ir_builder.h
> @@ -0,0 +1,36 @@
> +/*
> + * Copyright © 2012 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + */
> +
> +#include "ir.h"
> +
> +namespace ir_builder {
> +
> +ir_expression *expr(ir_expression_operation op,
> + ir_instruction *a, ir_instruction *b);
> +ir_expression *add(ir_instruction *a, ir_instruction *b);
> +ir_expression *sub(ir_instruction *a, ir_instruction *b);
> +ir_expression *mul(ir_instruction *a, ir_instruction *b);
> +ir_expression *dot(ir_instruction *a, ir_instruction *b);
> +ir_expression *saturate(ir_instruction *a);
> +
> +} /* namespace ir_builder */
> diff --git a/src/mesa/main/ff_fragment_shader.cpp b/src/mesa/main/ff_fragment_shader.cpp
> index 7b83043..cfee334 100644
> --- a/src/mesa/main/ff_fragment_shader.cpp
> +++ b/src/mesa/main/ff_fragment_shader.cpp
> @@ -45,12 +45,15 @@ extern "C" {
> #include "main/uniforms.h"
> #include "../glsl/glsl_types.h"
> #include "../glsl/ir.h"
> +#include "../glsl/ir_builder.h"
> #include "../glsl/glsl_symbol_table.h"
> #include "../glsl/glsl_parser_extras.h"
> #include "../glsl/ir_optimization.h"
> #include "../glsl/ir_print_visitor.h"
> #include "../program/ir_to_mesa.h"
>
> +using namespace ir_builder;
> +
> /*
> * Note on texture units:
> *
> @@ -621,9 +624,7 @@ emit_combine_source(struct texenv_fragment_program *p,
>
> switch (operand) {
> case OPR_ONE_MINUS_SRC_COLOR:
> - return new(p->mem_ctx) ir_expression(ir_binop_sub,
> - new(p->mem_ctx) ir_constant(1.0f),
> - src);
> + return sub(new(p->mem_ctx) ir_constant(1.0f), src);
>
> case OPR_SRC_ALPHA:
> return src->type->is_scalar()
> @@ -633,9 +634,7 @@ emit_combine_source(struct texenv_fragment_program *p,
> ir_rvalue *const scalar = (src->type->is_scalar())
> ? src : (ir_rvalue *) new(p->mem_ctx) ir_swizzle(src, 3, 3, 3, 3, 1);
>
> - return new(p->mem_ctx) ir_expression(ir_binop_sub,
> - new(p->mem_ctx) ir_constant(1.0f),
> - scalar);
> + return sub(new(p->mem_ctx) ir_constant(1.0f), scalar);
> }
>
> case OPR_ZERO:
> @@ -720,73 +719,54 @@ emit_combine(struct texenv_fragment_program *p,
> return src[0];
>
> case MODE_MODULATE:
> - return new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[1]);
> + return mul(src[0], src[1]);
>
> case MODE_ADD:
> - return new(p->mem_ctx) ir_expression(ir_binop_add, src[0], src[1]);
> + return add(src[0], src[1]);
>
> case MODE_ADD_SIGNED:
> - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add, src[0], src[1]);
> - return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0,
> - new(p->mem_ctx) ir_constant(-0.5f));
> + return add(add(src[0], src[1]), new(p->mem_ctx) ir_constant(-0.5f));
>
> case MODE_INTERPOLATE:
> /* Arg0 * (Arg2) + Arg1 * (1-Arg2) */
> - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[2]);
> -
> - tmp1 = new(p->mem_ctx) ir_expression(ir_binop_sub,
> - new(p->mem_ctx) ir_constant(1.0f),
> - src[2]->clone(p->mem_ctx, NULL));
> - tmp1 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[1], tmp1);
> -
> - return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, tmp1);
> + tmp0 = mul(src[0], src[2]);
> + tmp1 = mul(src[1], sub(new(p->mem_ctx) ir_constant(1.0f),
> + src[2]->clone(p->mem_ctx, NULL)));
> + return add(tmp0, tmp1);
>
> case MODE_SUBTRACT:
> - return new(p->mem_ctx) ir_expression(ir_binop_sub, src[0], src[1]);
> + return sub(src[0], src[1]);
>
> case MODE_DOT3_RGBA:
> case MODE_DOT3_RGBA_EXT:
> case MODE_DOT3_RGB_EXT:
> case MODE_DOT3_RGB: {
> - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0],
> - new(p->mem_ctx) ir_constant(2.0f));
> - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add, tmp0,
> - new(p->mem_ctx) ir_constant(-1.0f));
> + tmp0 = mul(src[0], new(p->mem_ctx) ir_constant(2.0f));
> + tmp0 = add(tmp0, new(p->mem_ctx) ir_constant(-1.0f));
> tmp0 = new(p->mem_ctx) ir_swizzle(smear(p, tmp0), 0, 1, 2, 3, 3);
>
> - tmp1 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[1],
> - new(p->mem_ctx) ir_constant(2.0f));
> - tmp1 = new(p->mem_ctx) ir_expression(ir_binop_add, tmp1,
> - new(p->mem_ctx) ir_constant(-1.0f));
> + tmp1 = mul(src[1], new(p->mem_ctx) ir_constant(2.0f));
> + tmp1 = add(tmp1, new(p->mem_ctx) ir_constant(-1.0f));
> tmp1 = new(p->mem_ctx) ir_swizzle(smear(p, tmp1), 0, 1, 2, 3, 3);
>
> - return new(p->mem_ctx) ir_expression(ir_binop_dot, tmp0, tmp1);
> + return dot(tmp0, tmp1);
> }
> case MODE_MODULATE_ADD_ATI:
> - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[2]);
> - return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, src[1]);
> + return add(mul(src[0], src[2]), src[1]);
>
> case MODE_MODULATE_SIGNED_ADD_ATI:
> - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[2]);
> - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, src[1]);
> - return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0,
> - new(p->mem_ctx) ir_constant(-0.5f));
> + return add(add(mul(src[0], src[2]), src[1]),
> + new(p->mem_ctx) ir_constant(-0.5f));
>
> case MODE_MODULATE_SUBTRACT_ATI:
> - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[2]);
> - return new(p->mem_ctx) ir_expression(ir_binop_sub, tmp0, src[1]);
> + return sub(mul(src[0], src[2]), src[1]);
>
> case MODE_ADD_PRODUCTS:
> - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[1]);
> - tmp1 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[2], src[3]);
> - return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, tmp1);
> + return add(mul(src[0], src[1]), mul(src[2], src[3]));
>
> case MODE_ADD_PRODUCTS_SIGNED:
> - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[1]);
> - tmp1 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[2], src[3]);
> - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, tmp1);
> - return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0,
> - new(p->mem_ctx) ir_constant(-0.5f));
> + return add(add(mul(src[0], src[1]), mul(src[2], src[3])),
> + new(p->mem_ctx) ir_constant(-0.5f));
>
> case MODE_BUMP_ENVMAP_ATI:
> /* special - not handled here */
> @@ -798,15 +778,6 @@ emit_combine(struct texenv_fragment_program *p,
> }
> }
>
> -static ir_rvalue *
> -saturate(struct texenv_fragment_program *p, ir_rvalue *val)
> -{
> - val = new(p->mem_ctx) ir_expression(ir_binop_min, val,
> - new(p->mem_ctx) ir_constant(1.0f));
> - return new(p->mem_ctx) ir_expression(ir_binop_max, val,
> - new(p->mem_ctx) ir_constant(0.0f));
> -}
> -
> /**
> * Generate instructions for one texture unit's env/combiner mode.
> */
> @@ -876,7 +847,7 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit)
> key->unit[unit].OptRGB);
> val = smear(p, val);
> if (rgb_saturate)
> - val = saturate(p, val);
> + val = saturate(val);
>
> deref = new(p->mem_ctx) ir_dereference_variable(temp_var);
> assign = new(p->mem_ctx) ir_assignment(deref, val);
> @@ -890,7 +861,7 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit)
> key->unit[unit].OptRGB);
> val = smear(p, val);
> if (rgb_saturate)
> - val = saturate(p, val);
> + val = saturate(val);
> deref = new(p->mem_ctx) ir_dereference_variable(temp_var);
> assign = new(p->mem_ctx) ir_assignment(deref, val);
> p->instructions->push_tail(assign);
> @@ -906,7 +877,7 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit)
> val = smear(p, val);
> val = new(p->mem_ctx) ir_swizzle(val, 0, 1, 2, 3, 3);
> if (rgb_saturate)
> - val = saturate(p, val);
> + val = saturate(val);
> deref = new(p->mem_ctx) ir_dereference_variable(temp_var);
> assign = new(p->mem_ctx) ir_assignment(deref, val, NULL, WRITEMASK_XYZ);
> p->instructions->push_tail(assign);
> @@ -918,7 +889,7 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit)
> val = smear(p, val);
> val = new(p->mem_ctx) ir_swizzle(val, 3, 3, 3, 3, 1);
> if (alpha_saturate)
> - val = saturate(p, val);
> + val = saturate(val);
> deref = new(p->mem_ctx) ir_dereference_variable(temp_var);
> assign = new(p->mem_ctx) ir_assignment(deref, val, NULL, WRITEMASK_W);
> p->instructions->push_tail(assign);
> @@ -945,8 +916,7 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit)
> (ir_constant_data *)const_data);
> }
>
> - return saturate(p, new(p->mem_ctx) ir_expression(ir_binop_mul,
> - deref, shift));
> + return saturate(mul(deref, shift));
> }
> else
> return deref;
> @@ -1185,18 +1155,16 @@ load_texunit_bumpmap( struct texenv_fragment_program *p, GLuint unit )
> bump = bump->clone(p->mem_ctx, NULL);
> bump_y = new(p->mem_ctx) ir_swizzle(bump, 1, 0, 0, 0, 1);
>
> - bump_x = new(p->mem_ctx) ir_expression(ir_binop_mul, bump_x, rot_mat_0);
> - bump_y = new(p->mem_ctx) ir_expression(ir_binop_mul, bump_y, rot_mat_1);
> + bump_x = mul(bump_x, rot_mat_0);
> + bump_y = mul(bump_y, rot_mat_1);
>
> ir_expression *expr;
> - expr = new(p->mem_ctx) ir_expression(ir_binop_add, bump_x, bump_y);
>
> deref = new(p->mem_ctx) ir_dereference_variable(bumped);
> - expr = new(p->mem_ctx) ir_expression(ir_binop_add,
> - new(p->mem_ctx) ir_swizzle(deref,
> - 0, 1, 1, 1,
> - 2),
> - expr);
> + expr = add(new(p->mem_ctx) ir_swizzle(deref,
> + 0, 1, 1, 1,
> + 2),
> + add(bump_x, bump_y));
>
> deref = new(p->mem_ctx) ir_dereference_variable(bumped);
> assign = new(p->mem_ctx) ir_assignment(deref, expr, NULL, WRITEMASK_XY);
> @@ -1255,11 +1223,11 @@ emit_fog_instructions(struct texenv_fragment_program *p,
> */
> temp = new(p->mem_ctx) ir_dereference_variable(oparams);
> temp = new(p->mem_ctx) ir_swizzle(temp, 0, 0, 0, 0, 1);
> - f = new(p->mem_ctx) ir_expression(ir_binop_mul, f, temp);
> + f = mul(f, temp);
>
> temp = new(p->mem_ctx) ir_dereference_variable(oparams);
> temp = new(p->mem_ctx) ir_swizzle(temp, 1, 0, 0, 0, 1);
> - f = new(p->mem_ctx) ir_expression(ir_binop_add, f, temp);
> + f = add(f, temp);
> break;
> case FOG_EXP:
> /* f = e^(-(density * fogcoord))
> @@ -1270,7 +1238,7 @@ emit_fog_instructions(struct texenv_fragment_program *p,
> */
> temp = new(p->mem_ctx) ir_dereference_variable(oparams);
> temp = new(p->mem_ctx) ir_swizzle(temp, 2, 0, 0, 0, 1);
> - f = new(p->mem_ctx) ir_expression(ir_binop_mul, f, temp);
> + f = mul(f, temp);
> f = new(p->mem_ctx) ir_expression(ir_unop_neg, f);
> f = new(p->mem_ctx) ir_expression(ir_unop_exp2, f);
> break;
> @@ -1288,8 +1256,7 @@ emit_fog_instructions(struct texenv_fragment_program *p,
>
> temp = new(p->mem_ctx) ir_dereference_variable(oparams);
> temp = new(p->mem_ctx) ir_swizzle(temp, 3, 0, 0, 0, 1);
> - f = new(p->mem_ctx) ir_expression(ir_binop_mul,
> - f, temp);
> + f = mul(f, temp);
>
> temp = new(p->mem_ctx) ir_dereference_variable(temp_var);
> ir_assignment *assign = new(p->mem_ctx) ir_assignment(temp, f);
> @@ -1297,30 +1264,27 @@ emit_fog_instructions(struct texenv_fragment_program *p,
>
> f = new(p->mem_ctx) ir_dereference_variable(temp_var);
> temp = new(p->mem_ctx) ir_dereference_variable(temp_var);
> - f = new(p->mem_ctx) ir_expression(ir_binop_mul, f, temp);
> + f = mul(f, temp);
> f = new(p->mem_ctx) ir_expression(ir_unop_neg, f);
> f = new(p->mem_ctx) ir_expression(ir_unop_exp2, f);
> break;
> }
>
> - f = saturate(p, f);
> + f = saturate(f);
>
> temp = new(p->mem_ctx) ir_dereference_variable(f_var);
> assign = new(p->mem_ctx) ir_assignment(temp, f);
> p->instructions->push_tail(assign);
>
> f = new(p->mem_ctx) ir_dereference_variable(f_var);
> - f = new(p->mem_ctx) ir_expression(ir_binop_sub,
> - new(p->mem_ctx) ir_constant(1.0f),
> - f);
> + f = sub(new(p->mem_ctx) ir_constant(1.0f), f);
> temp = new(p->mem_ctx) ir_dereference_variable(params);
> temp = new(p->mem_ctx) ir_dereference_record(temp, "color");
> temp = new(p->mem_ctx) ir_swizzle(temp, 0, 1, 2, 3, 3);
> - temp = new(p->mem_ctx) ir_expression(ir_binop_mul, temp, f);
> + temp = mul(temp, f);
>
> f = new(p->mem_ctx) ir_dereference_variable(f_var);
> - f = new(p->mem_ctx) ir_expression(ir_binop_mul, fragcolor, f);
> - f = new(p->mem_ctx) ir_expression(ir_binop_add, temp, f);
> + f = add(temp, mul(fragcolor, f));
>
> ir_dereference *deref = new(p->mem_ctx) ir_dereference_variable(fog_result);
> assign = new(p->mem_ctx) ir_assignment(deref, f, NULL, WRITEMASK_XYZ);
> @@ -1392,7 +1356,7 @@ emit_instructions(struct texenv_fragment_program *p)
> }
> secondary = new(p->mem_ctx) ir_swizzle(secondary, 0, 1, 2, 3, 3);
>
> - tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, secondary);
> + tmp0 = add(tmp0, secondary);
>
> deref = new(p->mem_ctx) ir_dereference_variable(spec_result);
> assign = new(p->mem_ctx) ir_assignment(deref, tmp0, NULL, WRITEMASK_XYZ);
More information about the mesa-dev
mailing list