mesa: Fix core GL genned-name handling for glBeginQuery().
[mesa.git] / src / mesa / main / ff_fragment_shader.cpp
index 50d6be70d403472831924ea4ef683757146796f6..3a80ab7f3b737d5b663634fc8197ad2ed263b565 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
  * All Rights Reserved.
  * Copyright 2009 VMware, Inc.  All Rights Reserved.
- * Copyright © 2010 Intel Corporation
+ * Copyright © 2010-2011 Intel Corporation
  * 
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the
@@ -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"
@@ -42,14 +43,18 @@ extern "C" {
 #include "program/programopt.h"
 #include "texenvprogram.h"
 }
+#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:
  *
@@ -108,7 +113,7 @@ struct state_key {
    /* NOTE: This array of structs must be last! (see "keySize" below) */
    struct {
       GLuint enabled:1;
-      GLuint source_index:3;   /**< TEXTURE_x_INDEX */
+      GLuint source_index:4;   /**< TEXTURE_x_INDEX */
       GLuint shadow:1;
       GLuint ScaleShiftRGB:2;
       GLuint ScaleShiftA:2;
@@ -294,7 +299,7 @@ need_saturate( GLuint mode )
 static GLuint translate_tex_src_bit( GLbitfield bit )
 {
    ASSERT(bit);
-   return _mesa_ffs(bit) - 1;
+   return ffs(bit) - 1;
 }
 
 
@@ -316,7 +321,7 @@ static GLbitfield get_fp_input_mask( struct gl_context *ctx )
    const GLboolean vertexShader =
       (ctx->Shader.CurrentVertexProgram &&
        ctx->Shader.CurrentVertexProgram->LinkStatus &&
-       ctx->Shader.CurrentVertexProgram->VertexProgram);
+       ctx->Shader.CurrentVertexProgram->_LinkedShaders[MESA_SHADER_VERTEX]);
    const GLboolean vertexProgram = ctx->VertexProgram._Enabled;
    GLbitfield fp_inputs = 0x0;
 
@@ -331,11 +336,10 @@ static GLbitfield get_fp_input_mask( struct gl_context *ctx )
       /* _NEW_RENDERMODE */
       fp_inputs = (FRAG_BIT_COL0 | FRAG_BIT_TEX0);
    }
-   else if (!(vertexProgram || vertexShader) ||
-            !ctx->VertexProgram._Current) {
+   else if (!(vertexProgram || vertexShader)) {
       /* Fixed function vertex logic */
-      /* _NEW_ARRAY */
-      GLbitfield varying_inputs = ctx->varying_vp_inputs;
+      /* _NEW_VARYING_VP_INPUTS */
+      GLbitfield64 varying_inputs = ctx->varying_vp_inputs;
 
       /* These get generated in the setup routine regardless of the
        * vertex program:
@@ -373,7 +377,7 @@ static GLbitfield get_fp_input_mask( struct gl_context *ctx )
    }
    else {
       /* calculate from vp->outputs */
-      struct gl_vertex_program *vprog;
+      struct gl_program *vprog;
       GLbitfield64 vp_outputs;
 
       /* Choose GLSL vertex shader over ARB vertex program.  Need this
@@ -381,11 +385,11 @@ static GLbitfield get_fp_input_mask( struct gl_context *ctx )
        * validation (see additional comments in state.c).
        */
       if (vertexShader)
-         vprog = ctx->Shader.CurrentVertexProgram->VertexProgram;
+         vprog = ctx->Shader.CurrentVertexProgram->_LinkedShaders[MESA_SHADER_VERTEX]->Program;
       else
-         vprog = ctx->VertexProgram.Current;
+         vprog = &ctx->VertexProgram.Current->Base;
 
-      vp_outputs = vprog->Base.OutputsWritten;
+      vp_outputs = vprog->OutputsWritten;
 
       /* These get generated in the setup routine regardless of the
        * vertex program:
@@ -425,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;
@@ -440,9 +446,10 @@ static GLuint make_state_key( struct gl_context *ctx,  struct state_key *key )
       key->unit[i].source_index =
          translate_tex_src_bit(texUnit->_ReallyEnabled);
 
-      key->unit[i].shadow = ((texObj->CompareMode == GL_COMPARE_R_TO_TEXTURE) &&
-                             ((format == GL_DEPTH_COMPONENT) || 
-                              (format == GL_DEPTH_STENCIL_EXT)));
+      key->unit[i].shadow =
+         ((samp->CompareMode == GL_COMPARE_R_TO_TEXTURE) &&
+          ((format == GL_DEPTH_COMPONENT) || 
+           (format == GL_DEPTH_STENCIL_EXT)));
 
       key->unit[i].NumArgsRGB = comb->_NumArgsRGB;
       key->unit[i].NumArgsA = comb->_NumArgsA;
@@ -489,6 +496,12 @@ static GLuint make_state_key( struct gl_context *ctx,  struct state_key *key )
    /* _NEW_BUFFERS */
    key->num_draw_buffers = ctx->DrawBuffer->_NumColorDrawBuffers;
 
+   /* _NEW_COLOR */
+   if (ctx->Color.AlphaEnabled && key->num_draw_buffers == 0) {
+      /* if alpha test is enabled we need to emit at least one color */
+      key->num_draw_buffers = 1;
+   }
+
    key->inputs_available = (inputs_available & inputs_referenced);
 
    /* compute size of state key, ignoring unused texture units */
@@ -501,27 +514,20 @@ 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;
-   struct gl_fragment_program *program;
-   exec_list *instructions;
    exec_list *top_instructions;
-   void *mem_ctx;
    struct state_key *state;
 
-   GLbitfield alu_temps;       /**< Track texture indirections, see spec. */
-   GLbitfield temps_output;    /**< Track texture indirections, see spec. */
-   GLbitfield temp_in_use;     /**< Tracks temporary regs which are in use. */
-   GLboolean error;
-
    ir_variable *src_texture[MAX_TEXTURE_COORD_UNITS];
    /* Reg containing each texture unit's sampled texture color,
     * else undef.
     */
 
    /* Texcoord override from bumpmapping. */
-   struct ir_variable *texcoord_tex[MAX_TEXTURE_COORD_UNITS];
+   ir_variable *texcoord_tex[MAX_TEXTURE_COORD_UNITS];
 
    /* Reg containing texcoord for a texture unit,
     * needed for bump mapping, else undef.
@@ -530,12 +536,35 @@ struct texenv_fragment_program {
    ir_rvalue *src_previous;    /**< Reg containing color from previous
                                 * stage.  May need to be decl'd.
                                 */
-
-   GLuint last_tex_stage;      /**< Number of last enabled texture unit */
 };
 
 static ir_rvalue *
-get_source(struct texenv_fragment_program *p,
+get_current_attrib(texenv_fragment_program *p, GLuint attrib)
+{
+   ir_variable *current;
+   ir_rvalue *val;
+
+   current = p->shader->symbols->get_variable("gl_CurrentAttribFragMESA");
+   current->max_array_access = MAX2(current->max_array_access, attrib);
+   val = new(p->mem_ctx) ir_dereference_variable(current);
+   ir_rvalue *index = new(p->mem_ctx) ir_constant(attrib);
+   return new(p->mem_ctx) ir_dereference_array(val, index);
+}
+
+static ir_rvalue *
+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");
+      assert(var);
+      return new(p->mem_ctx) ir_dereference_variable(var);
+   } else {
+      return get_current_attrib(p, VERT_ATTRIB_COLOR0);
+   }
+}
+
+static ir_rvalue *
+get_source(texenv_fragment_program *p,
           GLuint src, GLuint unit)
 {
    ir_variable *var;
@@ -574,9 +603,7 @@ get_source(struct texenv_fragment_program *p,
 
    case SRC_PREVIOUS:
       if (!p->src_previous) {
-        var = p->shader->symbols->get_variable("gl_Color");
-        assert(var);
-        return new(p->mem_ctx) ir_dereference_variable(var);
+        return get_gl_Color(p);
       } else {
         return p->src_previous->clone(p->mem_ctx, NULL);
       }
@@ -588,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)
@@ -599,19 +626,17 @@ 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);
-
-   case OPR_SRC_ALPHA: 
-      return new(p->mem_ctx) ir_swizzle(src, 3, 3, 3, 3, 1);
-
-   case OPR_ONE_MINUS_SRC_ALPHA: 
-      return new(p->mem_ctx) ir_expression(ir_binop_sub,
-                                          new(p->mem_ctx) ir_constant(1.0f),
-                                          new(p->mem_ctx) ir_swizzle(src,
-                                                                     3, 3,
-                                                                     3, 3, 1));
+      return sub(new(p->mem_ctx) ir_constant(1.0f), src);
+
+   case OPR_SRC_ALPHA:
+      return src->type->is_scalar() ? src : swizzle_w(src);
+
+   case OPR_ONE_MINUS_SRC_ALPHA: {
+      ir_rvalue *const scalar = src->type->is_scalar() ? src : swizzle_w(src);
+
+      return sub(new(p->mem_ctx) ir_constant(1.0f), scalar);
+   }
+
    case OPR_ZERO:
       return new(p->mem_ctx) ir_constant(0.0f);
    case OPR_ONE:
@@ -665,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,
@@ -694,73 +719,52 @@ 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 = 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 = 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);
+      tmp0 = mul(src[0], new(p->mem_ctx) ir_constant(2.0f));
+      tmp0 = add(tmp0, 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));
+
+      return dot(swizzle_xyz(smear(p, tmp0)), swizzle_xyz(smear(p, 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 */
@@ -772,20 +776,11 @@ 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.
  */
 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;
@@ -831,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
@@ -850,11 +840,9 @@ 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, NULL);
-      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) {
@@ -864,10 +852,8 @@ emit_texenv(struct texenv_fragment_program *p, GLuint unit)
                                    key->unit[unit].OptRGB);
       val = smear(p, val);
       if (rgb_saturate)
-        val = saturate(p, val);
-      deref = new(p->mem_ctx) ir_dereference_variable(temp_var);
-      assign = new(p->mem_ctx) ir_assignment(deref, val, NULL);
-      p->instructions->push_tail(assign);
+        val = saturate(val);
+      p->emit(assign(temp_var, val));
    }
    else {
       /* Need to do something to stop from re-emitting identical
@@ -877,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(p, 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);
+        val = saturate(val);
+      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(p, 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);
+        val = saturate(val);
+      p->emit(assign(temp_var, val, WRITEMASK_W));
    }
 
    deref = new(p->mem_ctx) ir_dereference_variable(temp_var);
@@ -910,17 +890,16 @@ 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);
       }
 
-      return saturate(p, new(p->mem_ctx) ir_expression(ir_binop_mul,
-                                                      deref, shift));
+      return saturate(mul(deref, shift));
    }
    else
       return deref;
@@ -930,132 +909,137 @@ 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 )
- {
-    ir_dereference *deref;
-    ir_assignment *assign;
-
-    if (p->src_texture[unit])
-       return;
-
-    const GLuint texTarget = p->state->unit[unit].source_index;
-    ir_rvalue *texcoord;
-
-    if (p->texcoord_tex[unit]) {
-       texcoord = new(p->mem_ctx) ir_dereference_variable(p->texcoord_tex[unit]);
-    }
-    else {
-       ir_variable *tc_array = p->shader->symbols->get_variable("gl_TexCoord");
-       assert(tc_array);
-       texcoord = new(p->mem_ctx) ir_dereference_variable(tc_array);
-       ir_rvalue *index = new(p->mem_ctx) ir_constant(unit);
-       texcoord = new(p->mem_ctx) ir_dereference_array(texcoord, index);
-       tc_array->max_array_access = MAX2(tc_array->max_array_access, 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),
-                                             NULL);
-       p->instructions->push_tail(assign);
-       return ;
-    }
-
-    const glsl_type *sampler_type = NULL;
-    int coords = 0;
-
-    switch (texTarget) {
-    case TEXTURE_1D_INDEX:
-       if (p->state->unit[unit].shadow)
-         sampler_type = p->shader->symbols->get_type("sampler1DShadow");
-       else
-         sampler_type = p->shader->symbols->get_type("sampler1D");
-       coords = 1;
-       break;
-    case TEXTURE_1D_ARRAY_INDEX:
-       if (p->state->unit[unit].shadow)
-         sampler_type = p->shader->symbols->get_type("sampler1DArrayShadow");
-       else
-         sampler_type = p->shader->symbols->get_type("sampler1DArray");
-       coords = 2;
-       break;
-    case TEXTURE_2D_INDEX:
-       if (p->state->unit[unit].shadow)
-         sampler_type = p->shader->symbols->get_type("sampler2DShadow");
-       else
-         sampler_type = p->shader->symbols->get_type("sampler2D");
-       coords = 2;
-       break;
-    case TEXTURE_2D_ARRAY_INDEX:
-       if (p->state->unit[unit].shadow)
-         sampler_type = p->shader->symbols->get_type("sampler2DArrayShadow");
-       else
-         sampler_type = p->shader->symbols->get_type("sampler2DArray");
-       coords = 3;
-       break;
-    case TEXTURE_RECT_INDEX:
-       if (p->state->unit[unit].shadow)
-         sampler_type = p->shader->symbols->get_type("sampler2DRectShadow");
-       else
-         sampler_type = p->shader->symbols->get_type("sampler2DRect");
-       coords = 2;
-       break;
-    case TEXTURE_3D_INDEX:
-       assert(!p->state->unit[unit].shadow);
-       sampler_type = p->shader->symbols->get_type("sampler3D");
-       coords = 3;
-       break;
-    case TEXTURE_CUBE_INDEX:
-       if (p->state->unit[unit].shadow)
-         sampler_type = p->shader->symbols->get_type("samplerCubeShadow");
-       else
-         sampler_type = p->shader->symbols->get_type("samplerCube");
-       coords = 3;
-       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]);
-
-    ir_texture *tex = new(p->mem_ctx) ir_texture(ir_tex);
-
-
-    char *sampler_name = ralloc_asprintf(p->mem_ctx, "sampler_%d", unit);
-    ir_variable *sampler = new(p->mem_ctx) ir_variable(sampler_type,
-                                                      sampler_name,
-                                                      ir_var_uniform);
-    p->top_instructions->push_head(sampler);
-    deref = new(p->mem_ctx) ir_dereference_variable(sampler);
-    tex->set_sampler(deref);
-
-    tex->coordinate = new(p->mem_ctx) ir_swizzle(texcoord, 0, 1, 2, 3, coords);
-
-    if (p->state->unit[unit].shadow) {
-       texcoord = texcoord->clone(p->mem_ctx, NULL);
-       tex->shadow_comparitor = new(p->mem_ctx) ir_swizzle(texcoord,
-                                                          coords, 0, 0, 0,
-                                                          1);
-       coords++;
-    }
-
-    texcoord = texcoord->clone(p->mem_ctx, NULL);
-    tex->projector = new(p->mem_ctx) ir_swizzle(texcoord, 3, 0, 0, 0, 1);
-
-    deref = new(p->mem_ctx) ir_dereference_variable(p->src_texture[unit]);
-    assign = new(p->mem_ctx) ir_assignment(deref, tex, NULL);
-    p->instructions->push_tail(assign);
- }
+static void load_texture( texenv_fragment_program *p, GLuint unit )
+{
+   ir_dereference *deref;
+
+   if (p->src_texture[unit])
+      return;
+
+   const GLuint texTarget = p->state->unit[unit].source_index;
+   ir_rvalue *texcoord;
+
+   if (!(p->state->inputs_available & (FRAG_BIT_TEX0 << unit))) {
+      texcoord = get_current_attrib(p, VERT_ATTRIB_TEX0 + unit);
+   } else if (p->texcoord_tex[unit]) {
+      texcoord = new(p->mem_ctx) ir_dereference_variable(p->texcoord_tex[unit]);
+   } else {
+      ir_variable *tc_array = p->shader->symbols->get_variable("gl_TexCoord");
+      assert(tc_array);
+      texcoord = new(p->mem_ctx) ir_dereference_variable(tc_array);
+      ir_rvalue *index = new(p->mem_ctx) ir_constant(unit);
+      texcoord = new(p->mem_ctx) ir_dereference_array(texcoord, index);
+      tc_array->max_array_access = MAX2(tc_array->max_array_access, unit);
+   }
+
+   if (!p->state->unit[unit].enabled) {
+      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 ;
+   }
+
+   const glsl_type *sampler_type = NULL;
+   int coords = 0;
+
+   switch (texTarget) {
+   case TEXTURE_1D_INDEX:
+      if (p->state->unit[unit].shadow)
+        sampler_type = p->shader->symbols->get_type("sampler1DShadow");
+      else
+        sampler_type = p->shader->symbols->get_type("sampler1D");
+      coords = 1;
+      break;
+   case TEXTURE_1D_ARRAY_INDEX:
+      if (p->state->unit[unit].shadow)
+        sampler_type = p->shader->symbols->get_type("sampler1DArrayShadow");
+      else
+        sampler_type = p->shader->symbols->get_type("sampler1DArray");
+      coords = 2;
+      break;
+   case TEXTURE_2D_INDEX:
+      if (p->state->unit[unit].shadow)
+        sampler_type = p->shader->symbols->get_type("sampler2DShadow");
+      else
+        sampler_type = p->shader->symbols->get_type("sampler2D");
+      coords = 2;
+      break;
+   case TEXTURE_2D_ARRAY_INDEX:
+      if (p->state->unit[unit].shadow)
+        sampler_type = p->shader->symbols->get_type("sampler2DArrayShadow");
+      else
+        sampler_type = p->shader->symbols->get_type("sampler2DArray");
+      coords = 3;
+      break;
+   case TEXTURE_RECT_INDEX:
+      if (p->state->unit[unit].shadow)
+        sampler_type = p->shader->symbols->get_type("sampler2DRectShadow");
+      else
+        sampler_type = p->shader->symbols->get_type("sampler2DRect");
+      coords = 2;
+      break;
+   case TEXTURE_3D_INDEX:
+      assert(!p->state->unit[unit].shadow);
+      sampler_type = p->shader->symbols->get_type("sampler3D");
+      coords = 3;
+      break;
+   case TEXTURE_CUBE_INDEX:
+      if (p->state->unit[unit].shadow)
+        sampler_type = p->shader->symbols->get_type("samplerCubeShadow");
+      else
+        sampler_type = p->shader->symbols->get_type("samplerCube");
+      coords = 3;
+      break;
+   case TEXTURE_EXTERNAL_INDEX:
+      assert(!p->state->unit[unit].shadow);
+      sampler_type = p->shader->symbols->get_type("samplerExternalOES");
+      coords = 2;
+      break;
+   }
+
+   p->src_texture[unit] = p->make_temp(glsl_type::vec4_type,
+                                      "tex");
+
+   ir_texture *tex = new(p->mem_ctx) ir_texture(ir_tex);
+
+
+   char *sampler_name = ralloc_asprintf(p->mem_ctx, "sampler_%d", unit);
+   ir_variable *sampler = new(p->mem_ctx) ir_variable(sampler_type,
+                                                     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);
+
+   tex->coordinate = new(p->mem_ctx) ir_swizzle(texcoord, 0, 1, 2, 3, coords);
+
+   if (p->state->unit[unit].shadow) {
+      texcoord = texcoord->clone(p->mem_ctx, NULL);
+      tex->shadow_comparitor = new(p->mem_ctx) ir_swizzle(texcoord,
+                                                         coords, 0, 0, 0,
+                                                         1);
+      coords++;
+   }
+
+   texcoord = texcoord->clone(p->mem_ctx, NULL);
+   tex->projector = swizzle_w(texcoord);
+
+   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) {
@@ -1085,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;
@@ -1105,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_MESABumpRotMatrix0");
-   rot_mat_1_var = p->shader->symbols->get_variable("gl_MESABumpRotMatrix1");
-   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);
@@ -1132,44 +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, NULL);
-   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(swizzle_x(bump), rot_mat_0);
+   bump_y = mul(swizzle_y(bump->clone(p->mem_ctx, NULL)), rot_mat_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);
-
-   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);
-
-   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;
 }
@@ -1182,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, NULL);
-   p->instructions->push_tail(assign);
-
-   temp = new(p->mem_ctx) ir_dereference_variable(fog_result);
-   fragcolor = new(p->mem_ctx) ir_swizzle(temp, 0, 1, 2, 3, 3);
-
-   oparams = p->shader->symbols->get_variable("gl_MESAFogParamsOptimized");
+   ir_variable *fog_result = p->make_temp(glsl_type::vec4_type, "fog_result");
+   p->emit(assign(fog_result, fragcolor));
+
+   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:
@@ -1222,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 = new(p->mem_ctx) ir_expression(ir_binop_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(mul(f, swizzle_x(oparams)), swizzle_y(oparams));
       break;
    case FOG_EXP:
       /* f = e^(-(density * fogcoord))
@@ -1237,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 = new(p->mem_ctx) ir_expression(ir_binop_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;
@@ -1250,56 +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 = new(p->mem_ctx) ir_expression(ir_binop_mul,
-                                       f, temp);
-
-      temp = new(p->mem_ctx) ir_dereference_variable(temp_var);
-      ir_assignment *assign = new(p->mem_ctx) ir_assignment(temp, f, NULL);
-      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 = new(p->mem_ctx) ir_expression(ir_binop_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(p, f);
+   p->emit(assign(f_var, saturate(f)));
 
-   temp = new(p->mem_ctx) ir_dereference_variable(f_var);
-   assign = new(p->mem_ctx) ir_assignment(temp, f, NULL);
-   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_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 = new(p->mem_ctx) ir_expression(ir_binop_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);
+   temp = mul(swizzle_xyz(temp), 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;
@@ -1320,7 +1235,6 @@ emit_instructions(struct texenv_fragment_program *p)
       for (unit = 0; unit < key->nr_enabled_units; unit++)
         if (key->unit[unit].enabled) {
            load_texunit_sources(p, unit);
-           p->last_tex_stage = unit;
         }
 
       /* Second pass - emit combine instructions to build final color:
@@ -1333,36 +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, *tmp1;
-      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, NULL);
-      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 *secondary =
-        p->shader->symbols->get_variable("gl_SecondaryColor");
-      assert(secondary);
-      deref = new(p->mem_ctx) ir_dereference_variable(secondary);
-      tmp1 = new(p->mem_ctx) ir_swizzle(deref, 0, 1, 2, 3, 3);
-
-      tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add,
-                                         tmp0, tmp1);
+      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 = swizzle_xyz(var);
+      } else {
+        secondary = swizzle_xyz(get_current_attrib(p, VERT_ATTRIB_COLOR1));
+      }
 
-      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);
    }
@@ -1373,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, NULL);
-   p->instructions->push_tail(assign);
+   p->emit(assign(frag_color, cf));
 }
 
 /**
@@ -1385,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;
@@ -1401,7 +1300,17 @@ create_new_program(struct gl_context *ctx, struct state_key *key)
    p.state = key;
    p.shader_program = ctx->Driver.NewShaderProgram(ctx, 0);
 
-   state->language_version = 120;
+   /* Tell the linker to ignore the fact that we're building a
+    * separate shader, in case we're in a GLES2 context that would
+    * normally reject that.  The real problem is that we're building a
+    * fixed function program in a GLES2 context at all, but that's a
+    * big mess to clean up.
+    */
+   p.shader_program->InternalSeparateShader = GL_TRUE;
+
+   state->language_version = 130;
+   if (ctx->Extensions.OES_EGL_image_external)
+      state->OES_EGL_image_external_enable = true;
    _mesa_glsl_initialize_types(state);
    _mesa_glsl_initialize_variables(p.instructions, state);
 
@@ -1412,10 +1321,8 @@ create_new_program(struct gl_context *ctx, struct state_key *key)
 
    p.src_previous = NULL;
 
-   p.last_tex_stage = 0;
-
    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 =
@@ -1429,7 +1336,7 @@ create_new_program(struct gl_context *ctx, struct state_key *key)
 
    validate_ir_tree(p.shader->ir);
 
-   while (do_common_optimization(p.shader->ir, false, 32))
+   while (do_common_optimization(p.shader->ir, false, false, 32))
       ;
    reparent_ir(p.shader->ir, p.shader->ir);
 
@@ -1446,23 +1353,18 @@ create_new_program(struct gl_context *ctx, struct state_key *key)
    /* Set the sampler uniforms, and relink to get them into the linked
     * program.
     */
-   struct gl_fragment_program *fp = p.shader_program->FragmentProgram;
-   for (unsigned int i = 0; i < MAX_TEXTURE_UNITS; i++) {
-      char *name = ralloc_asprintf(p.mem_ctx, "sampler_%d", i);
-      int loc = _mesa_get_uniform_location(ctx, p.shader_program, name);
-      if (loc != -1) {
-        /* 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.
-         */
-        loc = (loc & 0xffff) + (loc >> 16);
-        int sampler = fp->Base.Parameters->ParameterValues[loc][0];
-        fp->Base.SamplerUnits[sampler] = i;
-      }
-   }
-   _mesa_update_shader_textures_used(&fp->Base);
-   (void) ctx->Driver.ProgramStringNotify(ctx, fp->Base.Target, &fp->Base);
+   struct gl_shader *const fs =
+      p.shader_program->_LinkedShaders[MESA_SHADER_FRAGMENT];
+   struct gl_program *const fp = fs->Program;
+
+   _mesa_generate_parameters_list_for_uniforms(p.shader_program, fs,
+                                              fp->Parameters);
+
+   _mesa_associate_uniform_storage(ctx, p.shader_program, fp->Parameters);
+
+   _mesa_update_shader_textures_used(p.shader_program, 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",