mesa: Fix core GL genned-name handling for glBeginQuery().
[mesa.git] / src / mesa / main / ff_fragment_shader.cpp
index cfee334472109d870dd89b5863d978c0106c3c90..3a80ab7f3b737d5b663634fc8197ad2ed263b565 100644 (file)
@@ -33,6 +33,7 @@ extern "C" {
 #include "mtypes.h"
 #include "main/uniforms.h"
 #include "main/macros.h"
+#include "main/samplerobj.h"
 #include "program/program.h"
 #include "program/prog_parameter.h"
 #include "program/prog_cache.h"
@@ -337,7 +338,7 @@ static GLbitfield get_fp_input_mask( struct gl_context *ctx )
    }
    else if (!(vertexProgram || vertexShader)) {
       /* Fixed function vertex logic */
-      /* _NEW_ARRAY */
+      /* _NEW_VARYING_VP_INPUTS */
       GLbitfield64 varying_inputs = ctx->varying_vp_inputs;
 
       /* These get generated in the setup routine regardless of the
@@ -428,11 +429,13 @@ static GLuint make_state_key( struct gl_context *ctx,  struct state_key *key )
       const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
       const struct gl_texture_object *texObj = texUnit->_Current;
       const struct gl_tex_env_combine_state *comb = texUnit->_CurrentCombine;
+      const struct gl_sampler_object *samp;
       GLenum format;
 
       if (!texUnit->_ReallyEnabled || !texUnit->Enabled)
          continue;
 
+      samp = _mesa_get_samplerobj(ctx, i);
       format = texObj->Image[0][texObj->BaseLevel]->_BaseFormat;
 
       key->unit[i].enabled = 1;
@@ -444,7 +447,7 @@ static GLuint make_state_key( struct gl_context *ctx,  struct state_key *key )
          translate_tex_src_bit(texUnit->_ReallyEnabled);
 
       key->unit[i].shadow =
-         ((texObj->Sampler.CompareMode == GL_COMPARE_R_TO_TEXTURE) &&
+         ((samp->CompareMode == GL_COMPARE_R_TO_TEXTURE) &&
           ((format == GL_DEPTH_COMPONENT) || 
            (format == GL_DEPTH_STENCIL_EXT)));
 
@@ -511,12 +514,11 @@ static GLuint make_state_key( struct gl_context *ctx,  struct state_key *key )
 
 /** State used to build the fragment program:
  */
-struct texenv_fragment_program {
+class texenv_fragment_program : public ir_factory {
+public:
    struct gl_shader_program *shader_program;
    struct gl_shader *shader;
-   exec_list *instructions;
    exec_list *top_instructions;
-   void *mem_ctx;
    struct state_key *state;
 
    ir_variable *src_texture[MAX_TEXTURE_COORD_UNITS];
@@ -537,7 +539,7 @@ struct texenv_fragment_program {
 };
 
 static ir_rvalue *
-get_current_attrib(struct texenv_fragment_program *p, GLuint attrib)
+get_current_attrib(texenv_fragment_program *p, GLuint attrib)
 {
    ir_variable *current;
    ir_rvalue *val;
@@ -550,7 +552,7 @@ get_current_attrib(struct texenv_fragment_program *p, GLuint attrib)
 }
 
 static ir_rvalue *
-get_gl_Color(struct texenv_fragment_program *p)
+get_gl_Color(texenv_fragment_program *p)
 {
    if (p->state->inputs_available & FRAG_BIT_COL0) {
       ir_variable *var = p->shader->symbols->get_variable("gl_Color");
@@ -562,7 +564,7 @@ get_gl_Color(struct texenv_fragment_program *p)
 }
 
 static ir_rvalue *
-get_source(struct texenv_fragment_program *p,
+get_source(texenv_fragment_program *p,
           GLuint src, GLuint unit)
 {
    ir_variable *var;
@@ -613,7 +615,7 @@ get_source(struct texenv_fragment_program *p,
 }
 
 static ir_rvalue *
-emit_combine_source(struct texenv_fragment_program *p,
+emit_combine_source(texenv_fragment_program *p,
                    GLuint unit,
                    GLuint source,
                    GLuint operand)
@@ -627,12 +629,10 @@ emit_combine_source(struct texenv_fragment_program *p,
       return sub(new(p->mem_ctx) ir_constant(1.0f), src);
 
    case OPR_SRC_ALPHA:
-      return src->type->is_scalar()
-        ? src : (ir_rvalue *) new(p->mem_ctx) ir_swizzle(src, 3, 3, 3, 3, 1);
+      return src->type->is_scalar() ? src : swizzle_w(src);
 
    case OPR_ONE_MINUS_SRC_ALPHA: {
-      ir_rvalue *const scalar = (src->type->is_scalar())
-        ? src : (ir_rvalue *) new(p->mem_ctx) ir_swizzle(src, 3, 3, 3, 3, 1);
+      ir_rvalue *const scalar = src->type->is_scalar() ? src : swizzle_w(src);
 
       return sub(new(p->mem_ctx) ir_constant(1.0f), scalar);
    }
@@ -690,16 +690,16 @@ static GLboolean args_match( const struct state_key *key, GLuint unit )
 }
 
 static ir_rvalue *
-smear(struct texenv_fragment_program *p, ir_rvalue *val)
+smear(texenv_fragment_program *p, ir_rvalue *val)
 {
    if (!val->type->is_scalar())
       return val;
 
-   return new(p->mem_ctx) ir_swizzle(val, 0, 0, 0, 0, 4);
+   return swizzle_xxxx(val);
 }
 
 static ir_rvalue *
-emit_combine(struct texenv_fragment_program *p,
+emit_combine(texenv_fragment_program *p,
             GLuint unit,
             GLuint nr,
             GLuint mode,
@@ -743,13 +743,11 @@ emit_combine(struct texenv_fragment_program *p,
    case MODE_DOT3_RGB: {
       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 = 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 dot(tmp0, tmp1);
+      return dot(swizzle_xyz(smear(p, tmp0)), swizzle_xyz(smear(p, tmp1)));
    }
    case MODE_MODULATE_ADD_ATI:
       return add(mul(src[0], src[2]), src[1]);
@@ -782,7 +780,7 @@ emit_combine(struct texenv_fragment_program *p,
  * Generate instructions for one texture unit's env/combiner mode.
  */
 static ir_rvalue *
-emit_texenv(struct texenv_fragment_program *p, GLuint unit)
+emit_texenv(texenv_fragment_program *p, GLuint unit)
 {
    const struct state_key *key = p->state;
    GLboolean rgb_saturate, alpha_saturate;
@@ -828,13 +826,8 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit)
    else
       alpha_saturate = GL_FALSE;
 
-   ir_variable *temp_var = new(p->mem_ctx) ir_variable(glsl_type::vec4_type,
-                                                      "texenv_combine",
-                                                      ir_var_temporary);
-   p->instructions->push_tail(temp_var);
-
+   ir_variable *temp_var = p->make_temp(glsl_type::vec4_type, "texenv_combine");
    ir_dereference *deref;
-   ir_assignment *assign;
    ir_rvalue *val;
 
    /* Emit the RGB and A combine ops
@@ -849,9 +842,7 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit)
       if (rgb_saturate)
         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);
+      p->emit(assign(temp_var, val));
    }
    else if (key->unit[unit].ModeRGB == MODE_DOT3_RGBA_EXT ||
            key->unit[unit].ModeRGB == MODE_DOT3_RGBA) {
@@ -862,9 +853,7 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit)
       val = smear(p, val);
       if (rgb_saturate)
         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);
+      p->emit(assign(temp_var, val));
    }
    else {
       /* Need to do something to stop from re-emitting identical
@@ -874,25 +863,19 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit)
                         key->unit[unit].NumArgsRGB,
                         key->unit[unit].ModeRGB,
                         key->unit[unit].OptRGB);
-      val = smear(p, val);
-      val = new(p->mem_ctx) ir_swizzle(val, 0, 1, 2, 3, 3);
+      val = swizzle_xyz(smear(p, val));
       if (rgb_saturate)
         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);
+      p->emit(assign(temp_var, val, WRITEMASK_XYZ));
 
       val = emit_combine(p, unit,
                         key->unit[unit].NumArgsA,
                         key->unit[unit].ModeA,
                         key->unit[unit].OptA);
-      val = smear(p, val);
-      val = new(p->mem_ctx) ir_swizzle(val, 3, 3, 3, 3, 1);
+      val = swizzle_w(smear(p, val));
       if (alpha_saturate)
         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);
+      p->emit(assign(temp_var, val, WRITEMASK_W));
    }
 
    deref = new(p->mem_ctx) ir_dereference_variable(temp_var);
@@ -907,10 +890,10 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit)
       }
       else {
         float const_data[4] = {
-           1 << rgb_shift,
-           1 << rgb_shift,
-           1 << rgb_shift,
-           1 << alpha_shift
+           float(1 << rgb_shift),
+           float(1 << rgb_shift),
+           float(1 << rgb_shift),
+           float(1 << alpha_shift)
         };
         shift = new(p->mem_ctx) ir_constant(glsl_type::vec4_type,
                                             (ir_constant_data *)const_data);
@@ -926,10 +909,9 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit)
 /**
  * Generate instruction for getting a texture source term.
  */
-static void load_texture( struct texenv_fragment_program *p, GLuint unit )
+static void load_texture( texenv_fragment_program *p, GLuint unit )
 {
    ir_dereference *deref;
-   ir_assignment *assign;
 
    if (p->src_texture[unit])
       return;
@@ -951,15 +933,11 @@ static void load_texture( struct texenv_fragment_program *p, GLuint unit )
    }
 
    if (!p->state->unit[unit].enabled) {
-      p->src_texture[unit] = new(p->mem_ctx) ir_variable(glsl_type::vec4_type,
-                                                        "dummy_tex",
-                                                        ir_var_temporary);
-      p->instructions->push_tail(p->src_texture[unit]);
-
-      deref = new(p->mem_ctx) ir_dereference_variable(p->src_texture[unit]);
-      assign = new(p->mem_ctx) ir_assignment(deref,
-                                            new(p->mem_ctx) ir_constant(0.0f));
-      p->instructions->push_tail(assign);
+      p->src_texture[unit] = p->make_temp(glsl_type::vec4_type,
+                                         "dummy_tex");
+      p->emit(p->src_texture[unit]);
+
+      p->emit(assign(p->src_texture[unit], new(p->mem_ctx) ir_constant(0.0f)));
       return ;
    }
 
@@ -1021,10 +999,8 @@ static void load_texture( struct texenv_fragment_program *p, GLuint unit )
       break;
    }
 
-   p->src_texture[unit] = new(p->mem_ctx) ir_variable(glsl_type::vec4_type,
-                                                     "tex",
-                                                     ir_var_temporary);
-   p->instructions->push_tail(p->src_texture[unit]);
+   p->src_texture[unit] = p->make_temp(glsl_type::vec4_type,
+                                      "tex");
 
    ir_texture *tex = new(p->mem_ctx) ir_texture(ir_tex);
 
@@ -1034,6 +1010,15 @@ static void load_texture( struct texenv_fragment_program *p, GLuint unit )
                                                      sampler_name,
                                                      ir_var_uniform);
    p->top_instructions->push_head(sampler);
+
+   /* Set the texture unit for this sampler.  The linker will pick this value
+    * up and do-the-right-thing.
+    *
+    * NOTE: The cast to int is important.  Without it, the constant will have
+    * type uint, and things later on may get confused.
+    */
+   sampler->constant_value = new(p->mem_ctx) ir_constant(int(unit));
+
    deref = new(p->mem_ctx) ir_dereference_variable(sampler);
    tex->set_sampler(deref, glsl_type::vec4_type);
 
@@ -1048,15 +1033,13 @@ static void load_texture( struct texenv_fragment_program *p, GLuint unit )
    }
 
    texcoord = texcoord->clone(p->mem_ctx, NULL);
-   tex->projector = new(p->mem_ctx) ir_swizzle(texcoord, 3, 0, 0, 0, 1);
+   tex->projector = swizzle_w(texcoord);
 
-   deref = new(p->mem_ctx) ir_dereference_variable(p->src_texture[unit]);
-   assign = new(p->mem_ctx) ir_assignment(deref, tex);
-   p->instructions->push_tail(assign);
+   p->emit(assign(p->src_texture[unit], tex));
 }
 
 static void
-load_texenv_source(struct texenv_fragment_program *p,
+load_texenv_source(texenv_fragment_program *p,
                   GLuint src, GLuint unit)
 {
    switch (src) {
@@ -1086,7 +1069,7 @@ load_texenv_source(struct texenv_fragment_program *p,
  * Generate instructions for loading all texture source terms.
  */
 static GLboolean
-load_texunit_sources( struct texenv_fragment_program *p, GLuint unit )
+load_texunit_sources( texenv_fragment_program *p, GLuint unit )
 {
    const struct state_key *key = p->state;
    GLuint i;
@@ -1106,19 +1089,16 @@ load_texunit_sources( struct texenv_fragment_program *p, GLuint unit )
  * Generate instructions for loading bump map textures.
  */
 static void
-load_texunit_bumpmap( struct texenv_fragment_program *p, GLuint unit )
+load_texunit_bumpmap( texenv_fragment_program *p, GLuint unit )
 {
    const struct state_key *key = p->state;
    GLuint bumpedUnitNr = key->unit[unit].OptRGB[1].Source - SRC_TEXTURE0;
    ir_rvalue *bump;
    ir_rvalue *texcoord;
-   ir_variable *rot_mat_0_var, *rot_mat_1_var;
-   ir_dereference_variable *rot_mat_0, *rot_mat_1;
+   ir_variable *rot_mat_0, *rot_mat_1;
 
-   rot_mat_0_var = p->shader->symbols->get_variable("gl_BumpRotMatrix0MESA");
-   rot_mat_1_var = p->shader->symbols->get_variable("gl_BumpRotMatrix1MESA");
-   rot_mat_0 = new(p->mem_ctx) ir_dereference_variable(rot_mat_0_var);
-   rot_mat_1 = new(p->mem_ctx) ir_dereference_variable(rot_mat_1_var);
+   rot_mat_0 = p->shader->symbols->get_variable("gl_BumpRotMatrix0MESA");
+   rot_mat_1 = p->shader->symbols->get_variable("gl_BumpRotMatrix1MESA");
 
    ir_variable *tc_array = p->shader->symbols->get_variable("gl_TexCoord");
    assert(tc_array);
@@ -1133,42 +1113,22 @@ load_texunit_bumpmap( struct texenv_fragment_program *p, GLuint unit )
     * dest = Arg1 + (Arg0.xx * rotMat0) + (Arg0.yy * rotMat1)
     * note only 2 coords are affected the rest are left unchanged (mul by 0)
     */
-   ir_dereference *deref;
-   ir_assignment *assign;
    ir_rvalue *bump_x, *bump_y;
 
    texcoord = smear(p, texcoord);
 
    /* bump_texcoord = texcoord */
-   ir_variable *bumped = new(p->mem_ctx) ir_variable(texcoord->type,
-                                                    "bump_texcoord",
-                                                    ir_var_temporary);
-   p->instructions->push_tail(bumped);
-
-   deref = new(p->mem_ctx) ir_dereference_variable(bumped);
-   assign = new(p->mem_ctx) ir_assignment(deref, texcoord);
-   p->instructions->push_tail(assign);
+   ir_variable *bumped = p->make_temp(texcoord->type, "bump_texcoord");
+   p->emit(bumped);
+   p->emit(assign(bumped, texcoord));
 
    /* bump_texcoord.xy += arg0.x * rotmat0 + arg0.y * rotmat1 */
    bump = get_source(p, key->unit[unit].OptRGB[0].Source, unit);
-   bump_x = new(p->mem_ctx) ir_swizzle(bump, 0, 0, 0, 0, 1);
-   bump = bump->clone(p->mem_ctx, NULL);
-   bump_y = new(p->mem_ctx) ir_swizzle(bump, 1, 0, 0, 0, 1);
-
-   bump_x = mul(bump_x, rot_mat_0);
-   bump_y = mul(bump_y, rot_mat_1);
-
-   ir_expression *expr;
-
-   deref = new(p->mem_ctx) ir_dereference_variable(bumped);
-   expr = add(new(p->mem_ctx) ir_swizzle(deref,
-                                        0, 1, 1, 1,
-                                        2),
-             add(bump_x, bump_y));
+   bump_x = mul(swizzle_x(bump), rot_mat_0);
+   bump_y = mul(swizzle_y(bump->clone(p->mem_ctx, NULL)), rot_mat_1);
 
-   deref = new(p->mem_ctx) ir_dereference_variable(bumped);
-   assign = new(p->mem_ctx) ir_assignment(deref, expr, NULL, WRITEMASK_XY);
-   p->instructions->push_tail(assign);
+   p->emit(assign(bumped, add(swizzle_xy(bumped), add(bump_x, bump_y)),
+                 WRITEMASK_XY));
 
    p->texcoord_tex[bumpedUnitNr] = bumped;
 }
@@ -1181,38 +1141,29 @@ load_texunit_bumpmap( struct texenv_fragment_program *p, GLuint unit )
  * GL_FOG_COORDINATE_EXT is set to GL_FRAGMENT_DEPTH_EXT.
  */
 static ir_rvalue *
-emit_fog_instructions(struct texenv_fragment_program *p,
+emit_fog_instructions(texenv_fragment_program *p,
                      ir_rvalue *fragcolor)
 {
    struct state_key *key = p->state;
    ir_rvalue *f, *temp;
    ir_variable *params, *oparams;
    ir_variable *fogcoord;
-   ir_assignment *assign;
 
    /* Temporary storage for the whole fog result.  Fog calculations
     * only affect rgb so we're hanging on to the .a value of fragcolor
     * this way.
     */
-   ir_variable *fog_result = new(p->mem_ctx) ir_variable(glsl_type::vec4_type,
-                                                        "fog_result",
-                                                        ir_var_auto);
-   p->instructions->push_tail(fog_result);
-   temp = new(p->mem_ctx) ir_dereference_variable(fog_result);
-   assign = new(p->mem_ctx) ir_assignment(temp, fragcolor);
-   p->instructions->push_tail(assign);
+   ir_variable *fog_result = p->make_temp(glsl_type::vec4_type, "fog_result");
+   p->emit(assign(fog_result, fragcolor));
 
-   temp = new(p->mem_ctx) ir_dereference_variable(fog_result);
-   fragcolor = new(p->mem_ctx) ir_swizzle(temp, 0, 1, 2, 3, 3);
+   fragcolor = swizzle_xyz(fog_result);
 
    oparams = p->shader->symbols->get_variable("gl_FogParamsOptimizedMESA");
    fogcoord = p->shader->symbols->get_variable("gl_FogFragCoord");
    params = p->shader->symbols->get_variable("gl_Fog");
    f = new(p->mem_ctx) ir_dereference_variable(fogcoord);
 
-   ir_variable *f_var = new(p->mem_ctx) ir_variable(glsl_type::float_type,
-                                                   "fog_factor", ir_var_auto);
-   p->instructions->push_tail(f_var);
+   ir_variable *f_var = p->make_temp(glsl_type::float_type, "fog_factor");
 
    switch (key->fog_mode) {
    case FOG_LINEAR:
@@ -1221,13 +1172,7 @@ emit_fog_instructions(struct texenv_fragment_program *p,
        * gl_MesaFogParamsOptimized gives us (-1 / (end - start)) and
        * (end / (end - start)) so we can generate a single MAD.
        */
-      temp = new(p->mem_ctx) ir_dereference_variable(oparams);
-      temp = new(p->mem_ctx) ir_swizzle(temp, 0, 0, 0, 0, 1);
-      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 = add(f, temp);
+      f = add(mul(f, swizzle_x(oparams)), swizzle_y(oparams));
       break;
    case FOG_EXP:
       /* f = e^(-(density * fogcoord))
@@ -1236,9 +1181,7 @@ emit_fog_instructions(struct texenv_fragment_program *p,
        * use EXP2 which is generally the native instruction without
        * having to do any further math on the fog density uniform.
        */
-      temp = new(p->mem_ctx) ir_dereference_variable(oparams);
-      temp = new(p->mem_ctx) ir_swizzle(temp, 2, 0, 0, 0, 1);
-      f = mul(f, temp);
+      f = mul(f, swizzle_z(oparams));
       f = new(p->mem_ctx) ir_expression(ir_unop_neg, f);
       f = new(p->mem_ctx) ir_expression(ir_unop_exp2, f);
       break;
@@ -1249,52 +1192,29 @@ emit_fog_instructions(struct texenv_fragment_program *p,
        * can do this like FOG_EXP but with a squaring after the
        * multiply by density.
        */
-      ir_variable *temp_var = new(p->mem_ctx) ir_variable(glsl_type::float_type,
-                                                         "fog_temp",
-                                                         ir_var_auto);
-      p->instructions->push_tail(temp_var);
-
-      temp = new(p->mem_ctx) ir_dereference_variable(oparams);
-      temp = new(p->mem_ctx) ir_swizzle(temp, 3, 0, 0, 0, 1);
-      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);
-      p->instructions->push_tail(assign);
-
-      f = new(p->mem_ctx) ir_dereference_variable(temp_var);
-      temp = new(p->mem_ctx) ir_dereference_variable(temp_var);
-      f = mul(f, temp);
+      ir_variable *temp_var = p->make_temp(glsl_type::float_type, "fog_temp");
+      p->emit(assign(temp_var, mul(f, swizzle_w(oparams))));
+
+      f = mul(temp_var, temp_var);
       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(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);
+   p->emit(assign(f_var, saturate(f)));
 
-   f = new(p->mem_ctx) ir_dereference_variable(f_var);
-   f = sub(new(p->mem_ctx) ir_constant(1.0f), f);
+   f = sub(new(p->mem_ctx) ir_constant(1.0f), f_var);
    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 = mul(temp, f);
+   temp = mul(swizzle_xyz(temp), f);
 
-   f = new(p->mem_ctx) ir_dereference_variable(f_var);
-   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);
-   p->instructions->push_tail(assign);
+   p->emit(assign(fog_result, add(temp, mul(fragcolor, f_var)), WRITEMASK_XYZ));
 
    return new(p->mem_ctx) ir_dereference_variable(fog_result);
 }
 
 static void
-emit_instructions(struct texenv_fragment_program *p)
+emit_instructions(texenv_fragment_program *p)
 {
    struct state_key *key = p->state;
    GLuint unit;
@@ -1327,40 +1247,24 @@ emit_instructions(struct texenv_fragment_program *p)
    }
 
    ir_rvalue *cf = get_source(p, SRC_PREVIOUS, 0);
-   ir_dereference_variable *deref;
-   ir_assignment *assign;
 
    if (key->separate_specular) {
-      ir_rvalue *tmp0;
-      ir_variable *spec_result = new(p->mem_ctx) ir_variable(glsl_type::vec4_type,
-                                                           "specular_add",
-                                                           ir_var_temporary);
-
-      p->instructions->push_tail(spec_result);
-
-      deref = new(p->mem_ctx) ir_dereference_variable(spec_result);
-      assign = new(p->mem_ctx) ir_assignment(deref, cf);
-      p->instructions->push_tail(assign);
-
-      deref = new(p->mem_ctx) ir_dereference_variable(spec_result);
-      tmp0 = new(p->mem_ctx) ir_swizzle(deref, 0, 1, 2, 3, 3);
+      ir_variable *spec_result = p->make_temp(glsl_type::vec4_type,
+                                             "specular_add");
+      p->emit(assign(spec_result, cf));
 
       ir_rvalue *secondary;
       if (p->state->inputs_available & FRAG_BIT_COL1) {
         ir_variable *var =
            p->shader->symbols->get_variable("gl_SecondaryColor");
         assert(var);
-        secondary = new(p->mem_ctx) ir_dereference_variable(var);
+        secondary = swizzle_xyz(var);
       } else {
-        secondary = get_current_attrib(p, VERT_ATTRIB_COLOR1);
+        secondary = swizzle_xyz(get_current_attrib(p, VERT_ATTRIB_COLOR1));
       }
-      secondary = new(p->mem_ctx) ir_swizzle(secondary, 0, 1, 2, 3, 3);
-
-      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);
-      p->instructions->push_tail(assign);
+      p->emit(assign(spec_result, add(swizzle_xyz(spec_result), secondary),
+                    WRITEMASK_XYZ));
 
       cf = new(p->mem_ctx) ir_dereference_variable(spec_result);
    }
@@ -1371,9 +1275,7 @@ emit_instructions(struct texenv_fragment_program *p)
 
    ir_variable *frag_color = p->shader->symbols->get_variable("gl_FragColor");
    assert(frag_color);
-   deref = new(p->mem_ctx) ir_dereference_variable(frag_color);
-   assign = new(p->mem_ctx) ir_assignment(deref, cf);
-   p->instructions->push_tail(assign);
+   p->emit(assign(frag_color, cf));
 }
 
 /**
@@ -1383,11 +1285,10 @@ emit_instructions(struct texenv_fragment_program *p)
 static struct gl_shader_program *
 create_new_program(struct gl_context *ctx, struct state_key *key)
 {
-   struct texenv_fragment_program p;
+   texenv_fragment_program p;
    unsigned int unit;
    _mesa_glsl_parse_state *state;
 
-   memset(&p, 0, sizeof(p));
    p.mem_ctx = ralloc_context(NULL);
    p.shader = ctx->Driver.NewShader(ctx, 0, GL_FRAGMENT_SHADER);
    p.shader->ir = new(p.shader) exec_list;
@@ -1421,7 +1322,7 @@ create_new_program(struct gl_context *ctx, struct state_key *key)
    p.src_previous = NULL;
 
    ir_function *main_f = new(p.mem_ctx) ir_function("main");
-   p.instructions->push_tail(main_f);
+   p.emit(main_f);
    state->symbols->add_function(main_f);
 
    ir_function_signature *main_sig =
@@ -1461,40 +1362,9 @@ create_new_program(struct gl_context *ctx, struct state_key *key)
 
    _mesa_associate_uniform_storage(ctx, p.shader_program, fp->Parameters);
 
-   for (unsigned int i = 0; i < MAX_TEXTURE_UNITS; i++) {
-      /* Enough space for 'sampler_999\0'.
-       */
-      char name[12];
-
-      snprintf(name, sizeof(name), "sampler_%d", i);
-
-      int loc = _mesa_get_uniform_location(ctx, p.shader_program, name);
-      if (loc != -1) {
-        unsigned base;
-        unsigned idx;
-
-        /* Avoid using _mesa_uniform() because it flags state
-         * updates, so if we're generating this shader_program in a
-         * state update, we end up recursing.  Instead, just set the
-         * value, which is picked up at re-link.
-         */
-        _mesa_uniform_split_location_offset(loc, &base, &idx);
-        assert(idx == 0);
-
-        struct gl_uniform_storage *const storage =
-           &p.shader_program->UniformStorage[base];
-
-        /* Update the storage, the SamplerUnits in the shader program, and
-         * the SamplerUnits in the assembly shader.
-         */
-        storage->storage[idx].i = i;
-        fp->SamplerUnits[storage->sampler] = i;
-        p.shader_program->SamplerUnits[storage->sampler] = i;
-        _mesa_propagate_uniforms_to_driver_storage(storage, 0, 1);
-      }
-   }
    _mesa_update_shader_textures_used(p.shader_program, fp);
-   (void) ctx->Driver.ProgramStringNotify(ctx, fp->Target, fp);
+   if (ctx->Driver.SamplerUniformChange)
+      ctx->Driver.SamplerUniformChange(ctx, fp->Target, fp);
 
    if (!p.shader_program->LinkStatus)
       _mesa_problem(ctx, "Failed to link fixed function fragment shader: %s\n",