From 8fed2466e4056668a76a87cf935b5fbff8ae15ca Mon Sep 17 00:00:00 2001
From: Brian <brian.paul@tungstengraphics.com>
Date: Fri, 26 Oct 2007 19:19:09 -0600
Subject: Re-implement GLSL texture sampler variables.

GLSL sampler variables indicate which texture unit to use for TEX instructions.
Previously, this was baked into the fragment/vertex program and couldn't be
readily changed once set.
Now, SamplerUnits[] array indicates which texture unit is to be used for
each sampler variable.  These values are set with glUniform1i().
This is extra state that must be passed to the fragment/vertex program
executor at runtime.
---
 src/mesa/main/config.h                    |   1 +
 src/mesa/main/mtypes.h                    |   6 ++
 src/mesa/pipe/failover/fo_context.h       |   1 +
 src/mesa/pipe/failover/fo_state.c         |  14 ++++
 src/mesa/pipe/i915simple/i915_context.h   |   1 +
 src/mesa/pipe/i915simple/i915_state.c     |  10 +++
 src/mesa/pipe/p_context.h                 |   3 +
 src/mesa/pipe/softpipe/sp_context.c       |   1 +
 src/mesa/pipe/softpipe/sp_context.h       |   1 +
 src/mesa/pipe/softpipe/sp_quad_fs.c       |   1 +
 src/mesa/pipe/softpipe/sp_state.h         |   3 +
 src/mesa/pipe/softpipe/sp_state_sampler.c |  14 ++++
 src/mesa/pipe/tgsi/exec/tgsi_exec.c       |   5 +-
 src/mesa/pipe/tgsi/exec/tgsi_exec.h       |   1 +
 src/mesa/shader/prog_execute.c            |  16 ++---
 src/mesa/shader/prog_execute.h            |   2 +
 src/mesa/shader/prog_instruction.c        |  11 +++
 src/mesa/shader/prog_instruction.h        |   5 ++
 src/mesa/shader/prog_parameter.c          |   7 +-
 src/mesa/shader/prog_parameter.h          |   2 +-
 src/mesa/shader/prog_print.c              |   7 ++
 src/mesa/shader/program.c                 |   5 ++
 src/mesa/shader/shader_api.c              | 113 +++++++++++++++++++-----------
 src/mesa/shader/slang/slang_codegen.c     |  15 +++-
 src/mesa/shader/slang/slang_compile.c     |   6 ++
 src/mesa/shader/slang/slang_emit.c        |   6 +-
 src/mesa/shader/slang/slang_link.c        |  71 +++++++------------
 src/mesa/shader/slang/slang_link.h        |   4 --
 src/mesa/shader/slang/slang_typeinfo.h    |   1 +
 src/mesa/state_tracker/st_atom_sampler.c  |  33 ++++++++-
 src/mesa/swrast/s_fragprog.c              |   2 +
 31 files changed, 262 insertions(+), 106 deletions(-)

(limited to 'src/mesa')

diff --git a/src/mesa/main/config.h b/src/mesa/main/config.h
index cebef1c3832..8c642488454 100644
--- a/src/mesa/main/config.h
+++ b/src/mesa/main/config.h
@@ -207,6 +207,7 @@
 #define MAX_PROGRAM_ADDRESS_REGS 2
 #define MAX_UNIFORMS 128
 #define MAX_VARYING 8
+#define MAX_SAMPLERS 8
 /*@}*/
 
 /** For GL_ARB_vertex_shader */
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 514170dbcf0..8adc4e33731 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -1901,6 +1901,7 @@ struct gl_program
    GLbitfield InputsRead;     /**< Bitmask of which input regs are read */
    GLbitfield OutputsWritten; /**< Bitmask of which output regs are written to */
    GLbitfield TexturesUsed[MAX_TEXTURE_IMAGE_UNITS];  /**< TEXTURE_x_BIT bitmask */
+   GLbitfield SamplersUsed;   /**< Bitfield of which samplers are used */
    GLbitfield ShadowSamplers; /**< Texture units used for shadow sampling. */
 
    /** Named parameters, constants, etc. from program text */
@@ -1913,6 +1914,11 @@ struct gl_program
    /** Vertex program user-defined attributes */
    struct gl_program_parameter_list *Attributes;
 
+   /** Map from sampler unit to texture unit (set by glUniform1i()) */
+   GLubyte SamplerUnits[MAX_SAMPLERS];
+   /** Which texture target is being sampled (TEXTURE_1D/2D/3D/etc_INDEX) */
+   GLubyte SamplerTargets[MAX_SAMPLERS];
+
    /** Logical counts */
    /*@{*/
    GLuint NumInstructions;
diff --git a/src/mesa/pipe/failover/fo_context.h b/src/mesa/pipe/failover/fo_context.h
index 7a597013ab2..759b53ccbe4 100644
--- a/src/mesa/pipe/failover/fo_context.h
+++ b/src/mesa/pipe/failover/fo_context.h
@@ -84,6 +84,7 @@ struct failover_context {
    struct pipe_framebuffer_state framebuffer;
    struct pipe_poly_stipple poly_stipple;
    struct pipe_scissor_state scissor;
+   uint sampler_units[PIPE_MAX_SAMPLERS];
    struct pipe_mipmap_tree *texture[PIPE_MAX_SAMPLERS];
    struct pipe_viewport_state viewport;
    struct pipe_vertex_buffer vertex_buffer[PIPE_ATTRIB_MAX];
diff --git a/src/mesa/pipe/failover/fo_state.c b/src/mesa/pipe/failover/fo_state.c
index f63137f5913..2cd1a50b203 100644
--- a/src/mesa/pipe/failover/fo_state.c
+++ b/src/mesa/pipe/failover/fo_state.c
@@ -294,6 +294,19 @@ failover_set_polygon_stipple( struct pipe_context *pipe,
    failover->hw->set_polygon_stipple( failover->hw, stipple );
 }
 
+static void
+failover_set_sampler_units( struct pipe_context *pipe,
+                            uint num_samplers, const uint *units )
+{
+   struct failover_context *failover = failover_context(pipe);
+   uint i;
+
+   for (i = 0; i < num_samplers; i++)
+      failover->sampler_units[i] = units[i];
+   failover->dirty |= FO_NEW_SAMPLER;
+   failover->hw->set_sampler_units(failover->hw, num_samplers, units);
+}
+
 static void *
 failover_create_rasterizer_state(struct pipe_context *pipe,
                                  const struct pipe_rasterizer_state *templ)
@@ -470,6 +483,7 @@ failover_init_state_functions( struct failover_context *failover )
    failover->pipe.set_clear_color_state = failover_set_clear_color_state;
    failover->pipe.set_framebuffer_state = failover_set_framebuffer_state;
    failover->pipe.set_polygon_stipple = failover_set_polygon_stipple;
+   failover->pipe.set_sampler_units = failover_set_sampler_units;
    failover->pipe.set_scissor_state = failover_set_scissor_state;
    failover->pipe.set_texture_state = failover_set_texture_state;
    failover->pipe.set_viewport_state = failover_set_viewport_state;
diff --git a/src/mesa/pipe/i915simple/i915_context.h b/src/mesa/pipe/i915simple/i915_context.h
index a3dd392e755..5a3ecedad2b 100644
--- a/src/mesa/pipe/i915simple/i915_context.h
+++ b/src/mesa/pipe/i915simple/i915_context.h
@@ -173,6 +173,7 @@ struct i915_context
    struct pipe_framebuffer_state framebuffer;
    struct pipe_poly_stipple poly_stipple;
    struct pipe_scissor_state scissor;
+   uint sampler_units[PIPE_MAX_SAMPLERS];
    struct pipe_mipmap_tree *texture[PIPE_MAX_SAMPLERS];
    struct pipe_viewport_state viewport;
    struct pipe_vertex_buffer vertex_buffer[PIPE_ATTRIB_MAX];
diff --git a/src/mesa/pipe/i915simple/i915_state.c b/src/mesa/pipe/i915simple/i915_state.c
index 8da5662e3fe..05f8a6e1fd8 100644
--- a/src/mesa/pipe/i915simple/i915_state.c
+++ b/src/mesa/pipe/i915simple/i915_state.c
@@ -446,6 +446,15 @@ static void i915_set_polygon_stipple( struct pipe_context *pipe,
 {
 }
 
+static void i915_set_sampler_units(struct pipe_context *pipe,
+                                   uint numSamplers, const uint *units)
+{
+   struct i915_context *i915 = i915_context(pipe);
+   uint i;
+   for (i = 0; i < numSamplers; i++)
+      i915->sampler_units[i] = units[i];
+}
+
 static void * i915_create_fs_state(struct pipe_context *pipe,
                                    const struct pipe_shader_state *templ)
 {
@@ -765,6 +774,7 @@ i915_init_state_functions( struct i915_context *i915 )
    i915->pipe.set_feedback_buffer = i915_set_feedback_buffer;
 
    i915->pipe.set_polygon_stipple = i915_set_polygon_stipple;
+   i915->pipe.set_sampler_units = i915_set_sampler_units;
    i915->pipe.set_scissor_state = i915_set_scissor_state;
    i915->pipe.set_texture_state = i915_set_texture_state;
    i915->pipe.set_viewport_state = i915_set_viewport_state;
diff --git a/src/mesa/pipe/p_context.h b/src/mesa/pipe/p_context.h
index 3a041f158b0..5497f50f73d 100644
--- a/src/mesa/pipe/p_context.h
+++ b/src/mesa/pipe/p_context.h
@@ -148,6 +148,9 @@ struct pipe_context {
    void (*set_polygon_stipple)( struct pipe_context *,
 				const struct pipe_poly_stipple * );
 
+   void (*set_sampler_units)( struct pipe_context *,
+                              uint num_samplers, const uint *units );
+
    void (*set_scissor_state)( struct pipe_context *,
                               const struct pipe_scissor_state * );
 
diff --git a/src/mesa/pipe/softpipe/sp_context.c b/src/mesa/pipe/softpipe/sp_context.c
index 476d4ac01cc..58ef744f304 100644
--- a/src/mesa/pipe/softpipe/sp_context.c
+++ b/src/mesa/pipe/softpipe/sp_context.c
@@ -318,6 +318,7 @@ struct pipe_context *softpipe_create( struct pipe_winsys *pipe_winsys,
    softpipe->pipe.set_feedback_state = softpipe_set_feedback_state;
    softpipe->pipe.set_framebuffer_state = softpipe_set_framebuffer_state;
    softpipe->pipe.set_polygon_stipple = softpipe_set_polygon_stipple;
+   softpipe->pipe.set_sampler_units = softpipe_set_sampler_units;
    softpipe->pipe.set_scissor_state = softpipe_set_scissor_state;
    softpipe->pipe.set_texture_state = softpipe_set_texture_state;
    softpipe->pipe.set_viewport_state = softpipe_set_viewport_state;
diff --git a/src/mesa/pipe/softpipe/sp_context.h b/src/mesa/pipe/softpipe/sp_context.h
index 3e77bd6b856..88a418d3c7d 100644
--- a/src/mesa/pipe/softpipe/sp_context.h
+++ b/src/mesa/pipe/softpipe/sp_context.h
@@ -95,6 +95,7 @@ struct softpipe_context {
    struct pipe_viewport_state viewport;
    struct pipe_vertex_buffer vertex_buffer[PIPE_ATTRIB_MAX];
    struct pipe_vertex_element vertex_element[PIPE_ATTRIB_MAX];
+   uint sampler_units[PIPE_MAX_SAMPLERS];
    unsigned dirty;
 
    /*
diff --git a/src/mesa/pipe/softpipe/sp_quad_fs.c b/src/mesa/pipe/softpipe/sp_quad_fs.c
index 3371b109fcb..9b9504cd157 100644
--- a/src/mesa/pipe/softpipe/sp_quad_fs.c
+++ b/src/mesa/pipe/softpipe/sp_quad_fs.c
@@ -85,6 +85,7 @@ shade_quad(
    /* Consts does not require 16 byte alignment. */
    machine->Consts = softpipe->mapped_constants[PIPE_SHADER_FRAGMENT];
 
+   machine->SamplerUnits = softpipe->sampler_units;
    machine->InterpCoefs = quad->coef;
 
    machine->Inputs[0].xyzw[0].f[0] = fx;
diff --git a/src/mesa/pipe/softpipe/sp_state.h b/src/mesa/pipe/softpipe/sp_state.h
index c194f0ea0db..61532bcdebb 100644
--- a/src/mesa/pipe/softpipe/sp_state.h
+++ b/src/mesa/pipe/softpipe/sp_state.h
@@ -99,6 +99,9 @@ void softpipe_delete_vs_state(struct pipe_context *, void *);
 void softpipe_set_polygon_stipple( struct pipe_context *,
 				  const struct pipe_poly_stipple * );
 
+void softpipe_set_sampler_units( struct pipe_context *,
+                                 uint numSamplers, const uint *units );
+
 void softpipe_set_scissor_state( struct pipe_context *,
                                  const struct pipe_scissor_state * );
 
diff --git a/src/mesa/pipe/softpipe/sp_state_sampler.c b/src/mesa/pipe/softpipe/sp_state_sampler.c
index c00e815f2d4..e70eabd578b 100644
--- a/src/mesa/pipe/softpipe/sp_state_sampler.c
+++ b/src/mesa/pipe/softpipe/sp_state_sampler.c
@@ -78,3 +78,17 @@ softpipe_set_texture_state(struct pipe_context *pipe,
 
    softpipe->dirty |= SP_NEW_TEXTURE;
 }
+
+
+void
+softpipe_set_sampler_units(struct pipe_context *pipe,
+                           uint num_samplers, const uint *units )
+{
+   struct softpipe_context *softpipe = softpipe_context(pipe);
+   uint i;
+   for (i = 0; i < num_samplers; i++)
+      softpipe->sampler_units[i] = units[i];
+   softpipe->dirty |= SP_NEW_SAMPLER;
+}
+
+
diff --git a/src/mesa/pipe/tgsi/exec/tgsi_exec.c b/src/mesa/pipe/tgsi/exec/tgsi_exec.c
index 0125f40dd22..66a81b4bd83 100644
--- a/src/mesa/pipe/tgsi/exec/tgsi_exec.c
+++ b/src/mesa/pipe/tgsi/exec/tgsi_exec.c
@@ -1219,11 +1219,14 @@ exec_tex(struct tgsi_exec_machine *mach,
          const struct tgsi_full_instruction *inst,
          boolean biasLod)
 {
-   const uint unit = inst->FullSrcRegisters[1].SrcRegister.Index;
+   const uint sampler = inst->FullSrcRegisters[1].SrcRegister.Index;
+   const uint unit = mach->SamplerUnits[sampler];
    union tgsi_exec_channel r[8];
    uint chan_index;
    float lodBias;
 
+   //   printf("Sampler %u unit %u\n", sampler, unit);
+
    switch (inst->InstructionExtTexture.Texture) {
    case TGSI_TEXTURE_1D:
 
diff --git a/src/mesa/pipe/tgsi/exec/tgsi_exec.h b/src/mesa/pipe/tgsi/exec/tgsi_exec.h
index 1805e724874..38f9218520e 100644
--- a/src/mesa/pipe/tgsi/exec/tgsi_exec.h
+++ b/src/mesa/pipe/tgsi/exec/tgsi_exec.h
@@ -118,6 +118,7 @@ struct tgsi_exec_machine
    struct tgsi_exec_vector       *Temps;
    struct tgsi_exec_vector       *Addrs;
 
+   uint                          *SamplerUnits;
    struct tgsi_sampler           *Samplers;
 
    float                         Imms[TGSI_EXEC_NUM_IMMEDIATES][4];
diff --git a/src/mesa/shader/prog_execute.c b/src/mesa/shader/prog_execute.c
index 28d195d0ee9..bd64b57eb98 100644
--- a/src/mesa/shader/prog_execute.c
+++ b/src/mesa/shader/prog_execute.c
@@ -1316,22 +1316,22 @@ _mesa_execute_program(GLcontext * ctx,
              * The rest of the time, just use zero (until we get a more
              * sophisticated way of computing lambda).
              */
+            const GLuint unit = machine->Samplers[inst->TexSrcUnit];
             GLfloat coord[4], color[4], lambda;
 #if 0
             if (inst->SrcReg[0].File == PROGRAM_INPUT &&
-                inst->SrcReg[0].Index == FRAG_ATTRIB_TEX0 + inst->TexSrcUnit)
-               lambda = span->array->lambda[inst->TexSrcUnit][column];
+                inst->SrcReg[0].Index == FRAG_ATTRIB_TEX0 + unit)
+               lambda = span->array->lambda[unit][column];
             else
 #endif
                lambda = 0.0;
             fetch_vector4(&inst->SrcReg[0], machine, coord);
-            machine->FetchTexelLod(ctx, coord, lambda, inst->TexSrcUnit,
-                                   color);
+            machine->FetchTexelLod(ctx, coord, lambda, unit, color);
             if (DEBUG_PROG) {
                printf("TEX (%g, %g, %g, %g) = texture[%d][%g, %g, %g, %g], "
                       "lod %f\n",
                       color[0], color[1], color[2], color[3],
-                      inst->TexSrcUnit,
+                      unit,
                       coord[0], coord[1], coord[2], coord[3], lambda);
             }
             store_vector4(inst, machine, color);
@@ -1375,11 +1375,12 @@ _mesa_execute_program(GLcontext * ctx,
       case OPCODE_TXP:         /* GL_ARB_fragment_program only */
          /* Texture lookup w/ projective divide */
          {
+            const GLuint unit = machine->Samplers[inst->TexSrcUnit];
             GLfloat texcoord[4], color[4], lambda;
 #if 0
             if (inst->SrcReg[0].File == PROGRAM_INPUT &&
                 inst->SrcReg[0].Index == FRAG_ATTRIB_TEX0 + inst->TexSrcUnit)
-               lambda = span->array->lambda[inst->TexSrcUnit][column];
+               lambda = span->array->lambda[unit][column];
             else
 #endif
                lambda = 0.0;
@@ -1393,8 +1394,7 @@ _mesa_execute_program(GLcontext * ctx,
                texcoord[1] /= texcoord[3];
                texcoord[2] /= texcoord[3];
             }
-            machine->FetchTexelLod(ctx, texcoord, lambda,
-                                   inst->TexSrcUnit, color);
+            machine->FetchTexelLod(ctx, texcoord, lambda, unit, color);
             store_vector4(inst, machine, color);
          }
          break;
diff --git a/src/mesa/shader/prog_execute.h b/src/mesa/shader/prog_execute.h
index be29eceedaa..db7bcee5165 100644
--- a/src/mesa/shader/prog_execute.h
+++ b/src/mesa/shader/prog_execute.h
@@ -62,6 +62,8 @@ struct gl_program_machine
    GLuint CondCodes[4];  /**< COND_* value for x/y/z/w */
    GLint AddressReg[MAX_PROGRAM_ADDRESS_REGS][4];
 
+   GLuint *Samplers;  /** Array mapping sampler var to tex unit */
+
    GLuint CallStack[MAX_PROGRAM_CALL_DEPTH]; /**< For CAL/RET instructions */
    GLuint StackDepth; /**< Index/ptr to top of CallStack[] */
 
diff --git a/src/mesa/shader/prog_instruction.c b/src/mesa/shader/prog_instruction.c
index c84c76fd5bd..066129037a7 100644
--- a/src/mesa/shader/prog_instruction.c
+++ b/src/mesa/shader/prog_instruction.c
@@ -246,6 +246,17 @@ _mesa_num_inst_dst_regs(gl_inst_opcode opcode)
 }
 
 
+GLboolean
+_mesa_is_tex_instruction(gl_inst_opcode opcode)
+{
+   return (opcode == OPCODE_TEX ||
+           opcode == OPCODE_TXB ||
+           opcode == OPCODE_TXD ||
+           opcode == OPCODE_TXL ||
+           opcode == OPCODE_TXP);
+}
+
+
 /**
  * Return string name for given program opcode.
  */
diff --git a/src/mesa/shader/prog_instruction.h b/src/mesa/shader/prog_instruction.h
index 643969b367e..e8a2407ea85 100644
--- a/src/mesa/shader/prog_instruction.h
+++ b/src/mesa/shader/prog_instruction.h
@@ -413,11 +413,13 @@ struct prog_instruction
     */
    GLint BranchTarget;
 
+#if 0
    /**
     * For TEX instructions in shaders, the sampler to use for the
     * texture lookup.
     */
    GLint Sampler;
+#endif
 
    const char *Comment;
 };
@@ -443,6 +445,9 @@ _mesa_num_inst_src_regs(gl_inst_opcode opcode);
 extern GLuint
 _mesa_num_inst_dst_regs(gl_inst_opcode opcode);
 
+extern GLboolean
+_mesa_is_tex_instruction(gl_inst_opcode opcode);
+
 extern const char *
 _mesa_opcode_string(gl_inst_opcode opcode);
 
diff --git a/src/mesa/shader/prog_parameter.c b/src/mesa/shader/prog_parameter.c
index 9e3d3fecf22..b4008abbd95 100644
--- a/src/mesa/shader/prog_parameter.c
+++ b/src/mesa/shader/prog_parameter.c
@@ -283,22 +283,25 @@ _mesa_add_uniform(struct gl_program_parameter_list *paramList,
  * Add a sampler to the parameter list.
  * \param name  uniform's name
  * \param datatype  GL_SAMPLER_2D, GL_SAMPLER_2D_RECT_ARB, etc.
+ * \param index  the sampler number (as seen in TEX instructions)
  */
 GLint
 _mesa_add_sampler(struct gl_program_parameter_list *paramList,
-                  const char *name, GLenum datatype)
+                  const char *name, GLenum datatype, GLuint index)
 {
    GLint i = _mesa_lookup_parameter_index(paramList, -1, name);
    if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_SAMPLER) {
       ASSERT(paramList->Parameters[i].Size == 1);
       ASSERT(paramList->Parameters[i].DataType == datatype);
+      ASSERT(paramList->ParameterValues[i][0] == index);
       /* already in list */
       return i;
    }
    else {
+      GLfloat indexf = index;
       const GLint size = 1; /* a sampler is basically a texture unit number */
       i = _mesa_add_parameter(paramList, PROGRAM_SAMPLER, name,
-                              size, datatype, NULL, NULL);
+                              size, datatype, &indexf, NULL);
       return i;
    }
 }
diff --git a/src/mesa/shader/prog_parameter.h b/src/mesa/shader/prog_parameter.h
index 09ff851ea73..40c8c09e09b 100644
--- a/src/mesa/shader/prog_parameter.h
+++ b/src/mesa/shader/prog_parameter.h
@@ -104,7 +104,7 @@ _mesa_add_uniform(struct gl_program_parameter_list *paramList,
 
 extern GLint
 _mesa_add_sampler(struct gl_program_parameter_list *paramList,
-                  const char *name, GLenum datatype);
+                  const char *name, GLenum datatype, GLuint index);
 
 extern GLint
 _mesa_add_varying(struct gl_program_parameter_list *paramList,
diff --git a/src/mesa/shader/prog_print.c b/src/mesa/shader/prog_print.c
index e92837f739e..c421b1228bc 100644
--- a/src/mesa/shader/prog_print.c
+++ b/src/mesa/shader/prog_print.c
@@ -719,6 +719,8 @@ _mesa_print_program_opt(const struct gl_program *prog,
 void
 _mesa_print_program_parameters(GLcontext *ctx, const struct gl_program *prog)
 {
+   GLuint i;
+
    _mesa_printf("InputsRead: 0x%x\n", prog->InputsRead);
    _mesa_printf("OutputsWritten: 0x%x\n", prog->OutputsWritten);
    _mesa_printf("NumInstructions=%d\n", prog->NumInstructions);
@@ -726,6 +728,11 @@ _mesa_print_program_parameters(GLcontext *ctx, const struct gl_program *prog)
    _mesa_printf("NumParameters=%d\n", prog->NumParameters);
    _mesa_printf("NumAttributes=%d\n", prog->NumAttributes);
    _mesa_printf("NumAddressRegs=%d\n", prog->NumAddressRegs);
+   _mesa_printf("Samplers=[ ");
+   for (i = 0; i < MAX_SAMPLERS; i++) {
+      _mesa_printf("%d ", prog->SamplerUnits[i]);
+   }
+   _mesa_printf("]\n");
 	
    _mesa_load_state_parameters(ctx, prog->Parameters);
 			
diff --git a/src/mesa/shader/program.c b/src/mesa/shader/program.c
index 1f227390afd..cafc0dcfaa4 100644
--- a/src/mesa/shader/program.c
+++ b/src/mesa/shader/program.c
@@ -187,12 +187,17 @@ _mesa_init_program_struct( GLcontext *ctx, struct gl_program *prog,
 {
    (void) ctx;
    if (prog) {
+      GLuint i;
       _mesa_bzero(prog, sizeof(*prog));
       prog->Id = id;
       prog->Target = target;
       prog->Resident = GL_TRUE;
       prog->RefCount = 1;
       prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB;
+
+      /* default mapping from samplers to texture units */
+      for (i = 0; i < MAX_SAMPLERS; i++)
+         prog->SamplerUnits[i] = i;
    }
 
    return prog;
diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c
index 9f6c54dd4c5..bc5ecdaa156 100644
--- a/src/mesa/shader/shader_api.c
+++ b/src/mesa/shader/shader_api.c
@@ -1045,6 +1045,28 @@ _mesa_use_program(GLcontext *ctx, GLuint program)
 }
 
 
+
+/**
+ * Update the vertex and fragment program's TexturesUsed arrays.
+ */
+static void
+update_textures_used(struct gl_program *prog)
+{
+   GLuint s;
+
+   memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
+
+   for (s = 0; s < MAX_SAMPLERS; s++) {
+      if (prog->SamplersUsed & (1 << s)) {
+         GLuint u = prog->SamplerUnits[s];
+         GLuint t = prog->SamplerTargets[s];
+         assert(u < MAX_TEXTURE_IMAGE_UNITS);
+         prog->TexturesUsed[u] |= (1 << t);
+      }
+   }
+}
+
+
 /**
  * Called via ctx->Driver.Uniform().
  */
@@ -1067,26 +1089,6 @@ _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
 
    FLUSH_VERTICES(ctx, _NEW_PROGRAM);
 
-   /*
-    * If we're setting a sampler, we must use glUniformi1()!
-    */
-   if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
-      GLint unit;
-      if (type != GL_INT || count != 1) {
-         _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glUniform(only glUniform1i can be used "
-                     "to set sampler uniforms)");
-         return;
-      }
-      /* check that the sampler (tex unit index) is legal */
-      unit = ((GLint *) values)[0];
-      if (unit >= ctx->Const.MaxTextureImageUnits) {
-         _mesa_error(ctx, GL_INVALID_VALUE,
-                     "glUniform1(invalid sampler/tex unit index)");
-         return;
-      }
-   }
-
    if (count < 0) {
       _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
       return;
@@ -1119,32 +1121,61 @@ _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
       return;
    }
 
-   for (k = 0; k < count; k++) {
-      GLfloat *uniformVal = shProg->Uniforms->ParameterValues[location + k];
-      if (type == GL_INT ||
-          type == GL_INT_VEC2 ||
-          type == GL_INT_VEC3 ||
-          type == GL_INT_VEC4) {
-         const GLint *iValues = ((const GLint *) values) + k * elems;
-         for (i = 0; i < elems; i++) {
-            uniformVal[i] = (GLfloat) iValues[i];
-         }
+   if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
+      /* This controls which texture unit which is used by a sampler */
+      GLuint texUnit, sampler;
+
+      /* data type for setting samplers must be int */
+      if (type != GL_INT || count != 1) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glUniform(only glUniform1i can be used "
+                     "to set sampler uniforms)");
+         return;
       }
-      else {
-         const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
-         for (i = 0; i < elems; i++) {
-            uniformVal[i] = fValues[i];
-         }
+
+      sampler = (GLuint) shProg->Uniforms->ParameterValues[location][0];
+      texUnit = ((GLuint *) values)[0];
+
+      /* check that the sampler (tex unit index) is legal */
+      if (texUnit >= ctx->Const.MaxTextureImageUnits) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glUniform1(invalid sampler/tex unit index)");
+         return;
       }
-   }
 
-   if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
-      if (shProg->VertexProgram)
-         _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
-      if (shProg->FragmentProgram)
-         _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
+      if (shProg->VertexProgram) {
+         shProg->VertexProgram->Base.SamplerUnits[sampler] = texUnit;
+         update_textures_used(&shProg->VertexProgram->Base);
+      }
+      if (shProg->FragmentProgram) {
+         shProg->FragmentProgram->Base.SamplerUnits[sampler] = texUnit;
+         update_textures_used(&shProg->FragmentProgram->Base);
+      }
+
+
       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
    }
+   else {
+      /* ordinary uniform variable */
+      for (k = 0; k < count; k++) {
+         GLfloat *uniformVal = shProg->Uniforms->ParameterValues[location + k];
+         if (type == GL_INT ||
+             type == GL_INT_VEC2 ||
+             type == GL_INT_VEC3 ||
+             type == GL_INT_VEC4) {
+            const GLint *iValues = ((const GLint *) values) + k * elems;
+            for (i = 0; i < elems; i++) {
+               uniformVal[i] = (GLfloat) iValues[i];
+            }
+         }
+         else {
+            const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
+            for (i = 0; i < elems; i++) {
+               uniformVal[i] = fValues[i];
+            }
+         }
+      }
+   }
 }
 
 
diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c
index fb1f9d5a20a..767ba3ffb43 100644
--- a/src/mesa/shader/slang/slang_codegen.c
+++ b/src/mesa/shader/slang/slang_codegen.c
@@ -2874,14 +2874,23 @@ _slang_codegen_global_variable(slang_assemble_ctx *A, slang_variable *var,
    const GLint texIndex = sampler_to_texture_index(var->type.specifier.type);
 
    if (texIndex != -1) {
-      /* Texture sampler:
+      /* This is a texture sampler variable...
        * store->File = PROGRAM_SAMPLER
-       * store->Index = sampler uniform location
+       * store->Index = sampler number (0..7, typically)
        * store->Size = texture type index (1D, 2D, 3D, cube, etc)
        */
+#if 0
       GLint samplerUniform
          = _mesa_add_sampler(prog->Parameters, varName, datatype);
-      store = _slang_new_ir_storage(PROGRAM_SAMPLER, samplerUniform, texIndex);
+#elif 0
+      GLint samplerUniform
+         = _mesa_add_sampler(prog->Samplers, varName, datatype);
+      (void) _mesa_add_sampler(prog->Parameters, varName, datatype); /* dummy entry */
+#else
+      const GLint sampNum = A->numSamplers++;
+      _mesa_add_sampler(prog->Parameters, varName, datatype, sampNum);
+#endif
+      store = _slang_new_ir_storage(PROGRAM_SAMPLER, sampNum, texIndex);
       if (dbg) printf("SAMPLER ");
    }
    else if (var->type.qualifier == SLANG_QUAL_UNIFORM) {
diff --git a/src/mesa/shader/slang/slang_compile.c b/src/mesa/shader/slang/slang_compile.c
index 2be89a5ce05..bfb9ca4db6a 100644
--- a/src/mesa/shader/slang/slang_compile.c
+++ b/src/mesa/shader/slang/slang_compile.c
@@ -1618,6 +1618,7 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O,
       A.program = O->program;
       A.vartable = O->vartable;
       A.curFuncEndLabel = NULL;
+      A.numSamplers = 0;
       if (!_slang_codegen_global_variable(&A, var, C->type))
          return 0;
    }
@@ -1640,6 +1641,7 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O,
          A.space.funcs = O->funs;
          A.space.structs = O->structs;
          A.space.vars = O->vars;
+         A.numSamplers = 0;
          if (!initialize_global(&A, var))
             return 0;
       }
@@ -1773,6 +1775,7 @@ parse_function(slang_parse_ctx * C, slang_output_ctx * O, int definition,
       A.program = O->program;
       A.vartable = O->vartable;
       A.log = C->L;
+      A.numSamplers = 0;
 
       _slang_codegen_function(&A, *parsed_func_ret);
    }
@@ -2152,6 +2155,9 @@ _slang_compile(GLcontext *ctx, struct gl_shader *shader)
       shader->Programs[0]->Parameters = _mesa_new_parameter_list();
       shader->Programs[0]->Varying = _mesa_new_parameter_list();
       shader->Programs[0]->Attributes = _mesa_new_parameter_list();
+#if 0
+      shader->Programs[0]->Samplers = _mesa_new_parameter_list();
+#endif
    }
 
    slang_info_log_construct(&info_log);
diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c
index fe13f2865cd..2b08e7020f0 100644
--- a/src/mesa/shader/slang/slang_emit.c
+++ b/src/mesa/shader/slang/slang_emit.c
@@ -906,11 +906,15 @@ emit_tex(slang_emit_info *emitInfo, slang_ir_node *n)
    assert(n->Children[0]->Store->Size >= TEXTURE_1D_INDEX);
    assert(n->Children[0]->Store->Size <= TEXTURE_RECT_INDEX);
 
-   inst->Sampler = n->Children[0]->Store->Index; /* i.e. uniform's index */
    inst->TexSrcTarget = n->Children[0]->Store->Size;
+#if 0
    inst->TexSrcUnit = 27; /* Dummy value; the TexSrcUnit will be computed at
                            * link time, using the sampler uniform's value.
                            */
+   inst->Sampler = n->Children[0]->Store->Index; /* i.e. uniform's index */
+#else
+   inst->TexSrcUnit = n->Children[0]->Store->Index; /* i.e. uniform's index */
+#endif
    return inst;
 }
 
diff --git a/src/mesa/shader/slang/slang_link.c b/src/mesa/shader/slang/slang_link.c
index eaa29ba094e..32f71685537 100644
--- a/src/mesa/shader/slang/slang_link.c
+++ b/src/mesa/shader/slang/slang_link.c
@@ -144,10 +144,14 @@ is_uniform(GLuint file)
 }
 
 
+static GLuint shProg_NumSamplers = 0; /** XXX temporary */
+
+
 static GLboolean
 link_uniform_vars(struct gl_shader_program *shProg, struct gl_program *prog)
 {
    GLuint *map, i;
+   GLuint samplerMap[MAX_SAMPLERS];
 
 #if 0
    printf("================ pre link uniforms ===============\n");
@@ -168,10 +172,13 @@ link_uniform_vars(struct gl_shader_program *shProg, struct gl_program *prog)
       /* sanity check */
       assert(is_uniform(p->Type));
 
+      /* See if this uniform is already in the linked program's list */
       if (p->Name) {
+         /* this is a named uniform */
          j = _mesa_lookup_parameter_index(shProg->Uniforms, -1, p->Name);
       }
       else {
+         /* this is an unnamed constant */
          /*GLuint swizzle;*/
          ASSERT(p->Type == PROGRAM_CONSTANT);
          if (_mesa_lookup_parameter_constant(shProg->Uniforms, pVals,
@@ -184,7 +191,8 @@ link_uniform_vars(struct gl_shader_program *shProg, struct gl_program *prog)
       }
 
       if (j >= 0) {
-         /* already in list, check size XXX check this */
+         /* already in linked program's list */
+         /* check size XXX check this */
 #if 0
          assert(p->Size == shProg->Uniforms->Parameters[j].Size);
 #endif
@@ -205,7 +213,15 @@ link_uniform_vars(struct gl_shader_program *shProg, struct gl_program *prog)
             j = _mesa_add_uniform(shProg->Uniforms, p->Name, p->Size, p->DataType);
             break;
          case PROGRAM_SAMPLER:
-            j = _mesa_add_sampler(shProg->Uniforms, p->Name, p->DataType);
+            {
+               GLuint sampNum = shProg_NumSamplers++;
+               GLuint oldSampNum;
+               j = _mesa_add_sampler(shProg->Uniforms, p->Name,
+                                     p->DataType, sampNum);
+               oldSampNum = (GLuint) prog->Parameters->ParameterValues[i][0];
+               assert(oldSampNum < MAX_SAMPLERS);
+               samplerMap[oldSampNum] = sampNum;
+            }
             break;
          default:
             _mesa_problem(NULL, "bad parameter type in link_uniform_vars()");
@@ -243,6 +259,7 @@ link_uniform_vars(struct gl_shader_program *shProg, struct gl_program *prog)
    /* OK, now scan the program/shader instructions looking for uniform vars,
     * replacing the old index with the new index.
     */
+   prog->SamplersUsed = 0x0;
    for (i = 0; i < prog->NumInstructions; i++) {
       struct prog_instruction *inst = prog->Instructions + i;
       GLuint j;
@@ -257,14 +274,15 @@ link_uniform_vars(struct gl_shader_program *shProg, struct gl_program *prog)
          }
       }
 
-      if (inst->Opcode == OPCODE_TEX ||
-          inst->Opcode == OPCODE_TXB ||
-          inst->Opcode == OPCODE_TXP) {
+      if (_mesa_is_tex_instruction(inst->Opcode)) {
          /*
          printf("====== remap sampler from %d to %d\n",
                 inst->Sampler, map[ inst->Sampler ]);
          */
-         inst->Sampler = map[ inst->Sampler ];
+         /* here, texUnit is really samplerUnit */
+         inst->TexSrcUnit = samplerMap[inst->TexSrcUnit];
+         prog->SamplerTargets[inst->TexSrcUnit] = inst->TexSrcTarget;
+         prog->SamplersUsed |= (1 << inst->TexSrcUnit);
       }
    }
 
@@ -404,36 +422,6 @@ _slang_remap_attribute(struct gl_program *prog, GLuint oldAttrib, GLuint newAttr
 
 
 
-/**
- * Scan program for texture instructions, lookup sampler/uniform's value
- * to determine which texture unit to use.
- * Also, update the program's TexturesUsed[] array.
- */
-void
-_slang_resolve_samplers(struct gl_shader_program *shProg,
-                        struct gl_program *prog)
-{
-   GLuint i;
-
-   for (i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
-      prog->TexturesUsed[i] = 0;
-
-   for (i = 0; i < prog->NumInstructions; i++) {
-      struct prog_instruction *inst = prog->Instructions + i;
-      if (inst->Opcode == OPCODE_TEX ||
-          inst->Opcode == OPCODE_TXB ||
-          inst->Opcode == OPCODE_TXP) {
-         GLint sampleUnit = (GLint) shProg->Uniforms->ParameterValues[inst->Sampler][0];
-         assert(sampleUnit < MAX_TEXTURE_IMAGE_UNITS);
-         inst->TexSrcUnit = sampleUnit;
-
-         prog->TexturesUsed[inst->TexSrcUnit] |= (1 << inst->TexSrcTarget);
-      }
-   }
-}
-
-
-
 /** cast wrapper */
 static struct gl_vertex_program *
 vertex_program(struct gl_program *prog)
@@ -490,6 +478,8 @@ _slang_link(GLcontext *ctx,
    const struct gl_fragment_program *fragProg;
    GLuint i;
 
+   shProg_NumSamplers = 0; /** XXX temporary */
+
    _mesa_clear_shader_program_data(ctx, shProg);
 
    shProg->Uniforms = _mesa_new_parameter_list();
@@ -549,13 +539,6 @@ _slang_link(GLcontext *ctx,
       shProg->FragmentProgram->Base.Parameters = shProg->Uniforms;
    }
 
-   if (shProg->VertexProgram) {
-      _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
-   }
-   if (shProg->FragmentProgram) {
-      _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
-   }
-
    if (shProg->VertexProgram) {
       if (!_slang_resolve_attributes(shProg, &shProg->VertexProgram->Base)) {
          /*goto cleanup;*/
@@ -601,7 +584,7 @@ _slang_link(GLcontext *ctx,
       _mesa_print_program(&fragProg->Base);
       _mesa_print_program_parameters(ctx, &fragProg->Base);
 #endif
-#if 0
+#if 01
       printf("************** linked fragment prog\n");
       _mesa_print_program(&shProg->FragmentProgram->Base);
       _mesa_print_program_parameters(ctx, &shProg->FragmentProgram->Base);
diff --git a/src/mesa/shader/slang/slang_link.h b/src/mesa/shader/slang/slang_link.h
index 606b9e46b16..8ef8a6b4b3e 100644
--- a/src/mesa/shader/slang/slang_link.h
+++ b/src/mesa/shader/slang/slang_link.h
@@ -32,10 +32,6 @@ extern void
 _slang_link(GLcontext *ctx, GLhandleARB h,
             struct gl_shader_program *shProg);
 
-extern void
-_slang_resolve_samplers(struct gl_shader_program *shProg,
-                        struct gl_program *prog);
-
 extern void
 _slang_remap_attribute(struct gl_program *prog, GLuint oldAttrib,
                        GLuint newAttrib);
diff --git a/src/mesa/shader/slang/slang_typeinfo.h b/src/mesa/shader/slang/slang_typeinfo.h
index 587331e8b1e..ad5aa3e195e 100644
--- a/src/mesa/shader/slang/slang_typeinfo.h
+++ b/src/mesa/shader/slang/slang_typeinfo.h
@@ -65,6 +65,7 @@ typedef struct slang_assemble_ctx_
    struct slang_label_ *curFuncEndLabel;
    struct slang_ir_node_ *CurLoop;
    struct slang_function_ *CurFunction;
+   GLuint numSamplers;
 } slang_assemble_ctx;
 
 
diff --git a/src/mesa/state_tracker/st_atom_sampler.c b/src/mesa/state_tracker/st_atom_sampler.c
index 38de35933e8..80b8cae013e 100644
--- a/src/mesa/state_tracker/st_atom_sampler.c
+++ b/src/mesa/state_tracker/st_atom_sampler.c
@@ -113,6 +113,23 @@ gl_filter_to_img_filter(GLenum filter)
 }
 
 
+static struct gl_fragment_program *
+current_fragment_program(GLcontext *ctx)
+{
+   struct gl_fragment_program *f;
+
+   if (ctx->Shader.CurrentProgram &&
+       ctx->Shader.CurrentProgram->LinkStatus &&
+       ctx->Shader.CurrentProgram->FragmentProgram) {
+      f = ctx->Shader.CurrentProgram->FragmentProgram;
+   }
+   else {
+      f = ctx->FragmentProgram._Current;
+      assert(f);
+   }
+   return f;
+}
+
 
 static void 
 update_samplers(struct st_context *st)
@@ -165,13 +182,27 @@ update_samplers(struct st_context *st)
          st->pipe->bind_sampler_state(st->pipe, u, cso->data);
       }
    }
+
+
+   /* mapping from sampler vars to texture units */
+   {
+      struct gl_fragment_program *fprog = current_fragment_program(st->ctx);
+      const GLubyte *samplerUnits = fprog->Base.SamplerUnits;
+      uint sample_units[PIPE_MAX_SAMPLERS];
+      uint s;
+      for (s = 0; s < PIPE_MAX_SAMPLERS; s++) {
+         sample_units[s] = fprog->Base.SamplerUnits[s];
+      }
+
+      st->pipe->set_sampler_units(st->pipe, PIPE_MAX_SAMPLERS, sample_units);
+   }
 }
 
 
 const struct st_tracked_state st_update_sampler = {
    .name = "st_update_sampler",
    .dirty = {
-      .mesa = _NEW_TEXTURE,
+      .mesa = _NEW_TEXTURE | _NEW_PROGRAM,
       .st  = 0,
    },
    .update = update_samplers
diff --git a/src/mesa/swrast/s_fragprog.c b/src/mesa/swrast/s_fragprog.c
index 6656ebc0d0c..6ee8bfd0a5e 100644
--- a/src/mesa/swrast/s_fragprog.c
+++ b/src/mesa/swrast/s_fragprog.c
@@ -113,6 +113,8 @@ init_machine(GLcontext *ctx, struct gl_program_machine *machine,
    machine->DerivY = (GLfloat (*)[4]) span->attrStepY;
    machine->NumDeriv = FRAG_ATTRIB_MAX;
 
+   machine->Samplers = program->Base.SamplerUnits;
+
    /* if running a GLSL program (not ARB_fragment_program) */
    if (ctx->Shader.CurrentProgram) {
       /* Store front/back facing value in register FOGC.Y */
-- 
cgit v1.2.3