[Mesa-dev] [PATCH] gallivm: split sampler and texture state

sroland at vmware.com sroland at vmware.com
Thu Jan 24 18:48:09 PST 2013


From: Roland Scheidegger <sroland at vmware.com>

Split the sampler interface to use separate sampler and texture (sampler_view)
state. This is needed to support dx10-style sampling instructions.
This is not quite complete since both draw/llvmpipe don't really track
textures/samplers independently yet, as well as the gallivm code not quite
using the right sampler or texture index respectively (but it should work
for the sampling codes used by opengl).
We are however losing some optimizations in the process, apply_max_lod will
no longer work, and we potentially could end up with more (unnecessary)
recompiles (if switching textures with/without mipmaps only so it shouldn't
be too bad).

v2: don't use different callback structs for sampler/sampler view functions
(which just complicates things), fix up sampling code to actually use the
right texture or sampler index, and similar for llvmpipe/draw actually
distinguish between samplers and sampler views.
---
 src/gallium/auxiliary/draw/draw_llvm.c            |  129 +++++++++-----
 src/gallium/auxiliary/draw/draw_llvm.h            |   66 ++++++--
 src/gallium/auxiliary/draw/draw_llvm_sample.c     |   88 ++++++++--
 src/gallium/auxiliary/draw/draw_private.h         |    2 +-
 src/gallium/auxiliary/gallivm/lp_bld_sample.c     |  108 +++++++-----
 src/gallium/auxiliary/gallivm/lp_bld_sample.h     |   66 ++++++--
 src/gallium/auxiliary/gallivm/lp_bld_sample_aos.c |  104 ++++++------
 src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c |  187 ++++++++++++---------
 src/gallium/auxiliary/gallivm/lp_bld_tgsi.h       |    3 +-
 src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c   |    6 +-
 src/gallium/drivers/llvmpipe/lp_jit.c             |   54 ++++--
 src/gallium/drivers/llvmpipe/lp_jit.h             |   24 ++-
 src/gallium/drivers/llvmpipe/lp_setup.c           |   12 +-
 src/gallium/drivers/llvmpipe/lp_state_fs.c        |   84 ++++++---
 src/gallium/drivers/llvmpipe/lp_state_fs.h        |   17 +-
 src/gallium/drivers/llvmpipe/lp_state_setup.c     |   16 +-
 src/gallium/drivers/llvmpipe/lp_tex_sample.c      |  102 ++++++++---
 17 files changed, 711 insertions(+), 357 deletions(-)

diff --git a/src/gallium/auxiliary/draw/draw_llvm.c b/src/gallium/auxiliary/draw/draw_llvm.c
index a3a3bbf..9e5ff1c 100644
--- a/src/gallium/auxiliary/draw/draw_llvm.c
+++ b/src/gallium/auxiliary/draw/draw_llvm.c
@@ -85,11 +85,6 @@ create_jit_texture_type(struct gallivm_state *gallivm, const char *struct_name)
    elem_types[DRAW_JIT_TEXTURE_IMG_STRIDE] =
    elem_types[DRAW_JIT_TEXTURE_MIP_OFFSETS] =
       LLVMArrayType(int32_type, PIPE_MAX_TEXTURE_LEVELS);
-   elem_types[DRAW_JIT_TEXTURE_MIN_LOD] =
-   elem_types[DRAW_JIT_TEXTURE_MAX_LOD] =
-   elem_types[DRAW_JIT_TEXTURE_LOD_BIAS] = LLVMFloatTypeInContext(gallivm->context);
-   elem_types[DRAW_JIT_TEXTURE_BORDER_COLOR] = 
-      LLVMArrayType(LLVMFloatTypeInContext(gallivm->context), 4);
 
    texture_type = LLVMStructTypeInContext(gallivm->context, elem_types,
                                           Elements(elem_types), 0);
@@ -130,18 +125,6 @@ create_jit_texture_type(struct gallivm_state *gallivm, const char *struct_name)
    LP_CHECK_MEMBER_OFFSET(struct draw_jit_texture, mip_offsets,
                           target, texture_type,
                           DRAW_JIT_TEXTURE_MIP_OFFSETS);
-   LP_CHECK_MEMBER_OFFSET(struct draw_jit_texture, min_lod,
-                          target, texture_type,
-                          DRAW_JIT_TEXTURE_MIN_LOD);
-   LP_CHECK_MEMBER_OFFSET(struct draw_jit_texture, max_lod,
-                          target, texture_type,
-                          DRAW_JIT_TEXTURE_MAX_LOD);
-   LP_CHECK_MEMBER_OFFSET(struct draw_jit_texture, lod_bias,
-                          target, texture_type,
-                          DRAW_JIT_TEXTURE_LOD_BIAS);
-   LP_CHECK_MEMBER_OFFSET(struct draw_jit_texture, border_color,
-                          target, texture_type,
-                          DRAW_JIT_TEXTURE_BORDER_COLOR);
 
    LP_CHECK_STRUCT_SIZE(struct draw_jit_texture, target, texture_type);
 
@@ -150,15 +133,63 @@ create_jit_texture_type(struct gallivm_state *gallivm, const char *struct_name)
 
 
 /**
+ * Create LLVM type for struct draw_jit_sampler
+ */
+static LLVMTypeRef
+create_jit_sampler_type(struct gallivm_state *gallivm, const char *struct_name)
+{
+   LLVMTargetDataRef target = gallivm->target;
+   LLVMTypeRef sampler_type;
+   LLVMTypeRef elem_types[DRAW_JIT_SAMPLER_NUM_FIELDS];
+
+   elem_types[DRAW_JIT_SAMPLER_MIN_LOD] =
+   elem_types[DRAW_JIT_SAMPLER_MAX_LOD] =
+   elem_types[DRAW_JIT_SAMPLER_LOD_BIAS] = LLVMFloatTypeInContext(gallivm->context);
+   elem_types[DRAW_JIT_SAMPLER_BORDER_COLOR] =
+      LLVMArrayType(LLVMFloatTypeInContext(gallivm->context), 4);
+
+   sampler_type = LLVMStructTypeInContext(gallivm->context, elem_types,
+                                          Elements(elem_types), 0);
+
+#if HAVE_LLVM < 0x0300
+   LLVMAddTypeName(gallivm->module, struct_name, sampler_type);
+
+   /* Make sure the target's struct layout cache doesn't return
+    * stale/invalid data.
+    */
+   LLVMInvalidateStructLayout(gallivm->target, sampler_type);
+#endif
+
+   LP_CHECK_MEMBER_OFFSET(struct draw_jit_sampler, min_lod,
+                          target, sampler_type,
+                          DRAW_JIT_SAMPLER_MIN_LOD);
+   LP_CHECK_MEMBER_OFFSET(struct draw_jit_sampler, max_lod,
+                          target, sampler_type,
+                          DRAW_JIT_SAMPLER_MAX_LOD);
+   LP_CHECK_MEMBER_OFFSET(struct draw_jit_sampler, lod_bias,
+                          target, sampler_type,
+                          DRAW_JIT_SAMPLER_LOD_BIAS);
+   LP_CHECK_MEMBER_OFFSET(struct draw_jit_sampler, border_color,
+                          target, sampler_type,
+                          DRAW_JIT_SAMPLER_BORDER_COLOR);
+
+   LP_CHECK_STRUCT_SIZE(struct draw_jit_sampler, target, sampler_type);
+
+   return sampler_type;
+}
+
+
+/**
  * Create LLVM type for struct draw_jit_texture
  */
 static LLVMTypeRef
 create_jit_context_type(struct gallivm_state *gallivm,
-                        LLVMTypeRef texture_type, const char *struct_name)
+                        LLVMTypeRef texture_type, LLVMTypeRef sampler_type,
+                        const char *struct_name)
 {
    LLVMTargetDataRef target = gallivm->target;
    LLVMTypeRef float_type = LLVMFloatTypeInContext(gallivm->context);
-   LLVMTypeRef elem_types[5];
+   LLVMTypeRef elem_types[6];
    LLVMTypeRef context_type;
 
    elem_types[0] = LLVMArrayType(LLVMPointerType(float_type, 0), /* vs_constants */
@@ -168,7 +199,9 @@ create_jit_context_type(struct gallivm_state *gallivm,
                                                  DRAW_TOTAL_CLIP_PLANES), 0);
    elem_types[3] = LLVMPointerType(float_type, 0); /* viewport */
    elem_types[4] = LLVMArrayType(texture_type,
-                                 PIPE_MAX_SAMPLERS); /* textures */
+                                 PIPE_MAX_SHADER_SAMPLER_VIEWS); /* textures */
+   elem_types[5] = LLVMArrayType(sampler_type,
+                                 PIPE_MAX_SAMPLERS); /* samplers */
    context_type = LLVMStructTypeInContext(gallivm->context, elem_types,
                                           Elements(elem_types), 0);
 #if HAVE_LLVM < 0x0300
@@ -183,9 +216,14 @@ create_jit_context_type(struct gallivm_state *gallivm,
                           target, context_type, 1);
    LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, planes,
                           target, context_type, 2);
+   LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, viewport,
+                          target, context_type, 3);
    LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, textures,
                           target, context_type,
                           DRAW_JIT_CTX_TEXTURES);
+   LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, samplers,
+                          target, context_type,
+                          DRAW_JIT_CTX_SAMPLERS);
    LP_CHECK_STRUCT_SIZE(struct draw_jit_context,
                         target, context_type);
 
@@ -291,11 +329,13 @@ static void
 create_jit_types(struct draw_llvm_variant *variant)
 {
    struct gallivm_state *gallivm = variant->gallivm;
-   LLVMTypeRef texture_type, context_type, buffer_type, vb_type;
+   LLVMTypeRef texture_type, sampler_type, context_type, buffer_type, vb_type;
 
    texture_type = create_jit_texture_type(gallivm, "texture");
+   sampler_type = create_jit_sampler_type(gallivm, "sampler");
 
-   context_type = create_jit_context_type(gallivm, texture_type, "draw_jit_context");
+   context_type = create_jit_context_type(gallivm, texture_type, sampler_type,
+                                          "draw_jit_context");
    variant->context_ptr_type = LLVMPointerType(context_type, 0);
 
    buffer_type = LLVMPointerType(LLVMIntTypeInContext(gallivm->context, 8), 0);
@@ -1182,8 +1222,8 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant,
 
    /* code generated texture sampling */
    sampler = draw_llvm_sampler_soa_create(
-      draw_llvm_variant_key_samplers(&variant->key),
-      context_ptr);
+                draw_llvm_variant_key_samplers(&variant->key),
+                context_ptr);
 
    if (elts) {
       start = zero;
@@ -1319,7 +1359,7 @@ draw_llvm_make_variant_key(struct draw_llvm *llvm, char *store)
 {
    unsigned i;
    struct draw_llvm_variant_key *key;
-   struct lp_sampler_static_state *sampler;
+   struct draw_sampler_static_state *draw_sampler;
 
    key = (struct draw_llvm_variant_key *)store;
 
@@ -1345,19 +1385,29 @@ draw_llvm_make_variant_key(struct draw_llvm *llvm, char *store)
     * sampler array.
     */
    key->nr_samplers = llvm->draw->vs.vertex_shader->info.file_max[TGSI_FILE_SAMPLER] + 1;
+   if (llvm->draw->vs.vertex_shader->info.file_max[TGSI_FILE_SAMPLER_VIEW] != -1) {
+      key->nr_sampler_views =
+         llvm->draw->vs.vertex_shader->info.file_max[TGSI_FILE_SAMPLER_VIEW] + 1;
+   }
+   else {
+      key->nr_sampler_views = key->nr_samplers;
+   }
 
-   sampler = draw_llvm_variant_key_samplers(key);
+   draw_sampler = draw_llvm_variant_key_samplers(key);
 
    memcpy(key->vertex_element,
           llvm->draw->pt.vertex_element,
           sizeof(struct pipe_vertex_element) * key->nr_vertex_elements);
-   
-   memset(sampler, 0, key->nr_samplers * sizeof *sampler);
+
+   memset(draw_sampler, 0, MAX2(key->nr_samplers, key->nr_sampler_views) * sizeof *draw_sampler);
 
    for (i = 0 ; i < key->nr_samplers; i++) {
-      lp_sampler_static_state(&sampler[i],
-			      llvm->draw->sampler_views[PIPE_SHADER_VERTEX][i],
-			      llvm->draw->samplers[PIPE_SHADER_VERTEX][i]);
+      lp_sampler_static_sampler_state(&draw_sampler[i].sampler_state,
+                                      llvm->draw->samplers[PIPE_SHADER_VERTEX][i]);
+   }
+   for (i = 0 ; i < key->nr_sampler_views; i++) {
+      lp_sampler_static_texture_state(&draw_sampler[i].texture_state,
+                                      llvm->draw->sampler_views[PIPE_SHADER_VERTEX][i]);
    }
 
    return key;
@@ -1368,7 +1418,7 @@ void
 draw_llvm_dump_variant_key(struct draw_llvm_variant_key *key)
 {
    unsigned i;
-   struct lp_sampler_static_state *sampler = draw_llvm_variant_key_samplers(key);
+   struct draw_sampler_static_state *sampler = draw_llvm_variant_key_samplers(key);
 
    debug_printf("clamp_vertex_color = %u\n", key->clamp_vertex_color);
    debug_printf("clip_xy = %u\n", key->clip_xy);
@@ -1386,8 +1436,8 @@ draw_llvm_dump_variant_key(struct draw_llvm_variant_key *key)
       debug_printf("vertex_element[%i].src_format = %s\n", i, util_format_name(key->vertex_element[i].src_format));
    }
 
-   for (i = 0 ; i < key->nr_samplers; i++) {
-      debug_printf("sampler[%i].src_format = %s\n", i, util_format_name(sampler[i].format));
+   for (i = 0 ; i < key->nr_sampler_views; i++) {
+      debug_printf("sampler[%i].src_format = %s\n", i, util_format_name(sampler[i].texture_state.format));
    }
 }
 
@@ -1428,17 +1478,16 @@ void
 draw_llvm_set_sampler_state(struct draw_context *draw)
 {
    unsigned i;
-
    for (i = 0; i < draw->num_samplers[PIPE_SHADER_VERTEX]; i++) {
-      struct draw_jit_texture *jit_tex = &draw->llvm->jit_context.textures[i];
+      struct draw_jit_sampler *jit_sam = &draw->llvm->jit_context.samplers[i];
 
       if (draw->samplers[i]) {
          const struct pipe_sampler_state *s
             = draw->samplers[PIPE_SHADER_VERTEX][i];
-         jit_tex->min_lod = s->min_lod;
-         jit_tex->max_lod = s->max_lod;
-         jit_tex->lod_bias = s->lod_bias;
-         COPY_4V(jit_tex->border_color, s->border_color.f);
+         jit_sam->min_lod = s->min_lod;
+         jit_sam->max_lod = s->max_lod;
+         jit_sam->lod_bias = s->lod_bias;
+         COPY_4V(jit_sam->border_color, s->border_color.f);
       }
    }
 }
diff --git a/src/gallium/auxiliary/draw/draw_llvm.h b/src/gallium/auxiliary/draw/draw_llvm.h
index 892973c..a664857 100644
--- a/src/gallium/auxiliary/draw/draw_llvm.h
+++ b/src/gallium/auxiliary/draw/draw_llvm.h
@@ -52,12 +52,30 @@ struct draw_jit_texture
    uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS];
    uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS];
    uint32_t mip_offsets[PIPE_MAX_TEXTURE_LEVELS];
+};
+
+
+struct draw_sampler_static_state
+{
+   /*
+    * These attributes are effectively interleaved for more sane key handling.
+    * However, there might be lots of null space if the amount of samplers and
+    * textures isn't the same.
+    */
+   struct lp_static_sampler_state sampler_state;
+   struct lp_static_texture_state texture_state;
+};
+
+
+struct draw_jit_sampler
+{
    float min_lod;
    float max_lod;
    float lod_bias;
    float border_color[4];
 };
 
+
 enum {
    DRAW_JIT_TEXTURE_WIDTH = 0,
    DRAW_JIT_TEXTURE_HEIGHT,
@@ -68,13 +86,19 @@ enum {
    DRAW_JIT_TEXTURE_ROW_STRIDE,
    DRAW_JIT_TEXTURE_IMG_STRIDE,
    DRAW_JIT_TEXTURE_MIP_OFFSETS,
-   DRAW_JIT_TEXTURE_MIN_LOD,
-   DRAW_JIT_TEXTURE_MAX_LOD,
-   DRAW_JIT_TEXTURE_LOD_BIAS,
-   DRAW_JIT_TEXTURE_BORDER_COLOR,
    DRAW_JIT_TEXTURE_NUM_FIELDS  /* number of fields above */
 };
 
+
+enum {
+   DRAW_JIT_SAMPLER_MIN_LOD,
+   DRAW_JIT_SAMPLER_MAX_LOD,
+   DRAW_JIT_SAMPLER_LOD_BIAS,
+   DRAW_JIT_SAMPLER_BORDER_COLOR,
+   DRAW_JIT_SAMPLER_NUM_FIELDS  /* number of fields above */
+};
+
+
 enum {
    DRAW_JIT_VERTEX_VERTEX_ID = 0,
    DRAW_JIT_VERTEX_CLIP,
@@ -82,6 +106,9 @@ enum {
    DRAW_JIT_VERTEX_DATA
 };
 
+#define DRAW_JIT_CTX_TEXTURES 4
+#define DRAW_JIT_CTX_SAMPLERS 5
+
 /**
  * This structure is passed directly to the generated vertex shader.
  *
@@ -100,7 +127,8 @@ struct draw_jit_context
    float (*planes) [DRAW_TOTAL_CLIP_PLANES][4];
    float *viewport;
 
-   struct draw_jit_texture textures[PIPE_MAX_SAMPLERS];
+   struct draw_jit_texture textures[PIPE_MAX_SHADER_SAMPLER_VIEWS];
+   struct draw_jit_sampler samplers[PIPE_MAX_SAMPLERS];
 };
 
 
@@ -117,10 +145,14 @@ struct draw_jit_context
    lp_build_struct_get(_gallivm, _ptr, 3, "viewport")
 
 #define DRAW_JIT_CTX_TEXTURES 4
+#define DRAW_JIT_CTX_SAMPLERS 5
 
 #define draw_jit_context_textures(_gallivm, _ptr) \
    lp_build_struct_get_ptr(_gallivm, _ptr, DRAW_JIT_CTX_TEXTURES, "textures")
 
+#define draw_jit_context_samplers(_gallivm, _ptr) \
+   lp_build_struct_get_ptr(_gallivm, _ptr, DRAW_JIT_CTX_SAMPLERS, "samplers")
+
 #define draw_jit_header_id(_gallivm, _ptr)              \
    lp_build_struct_get_ptr(_gallivm, _ptr, DRAW_JIT_VERTEX_VERTEX_ID, "id")
 
@@ -166,6 +198,7 @@ struct draw_llvm_variant_key
 {
    unsigned nr_vertex_elements:8;
    unsigned nr_samplers:8;
+   unsigned nr_sampler_views:8;
    unsigned clamp_vertex_color:1;
    unsigned clip_xy:1;
    unsigned clip_z:1;
@@ -174,7 +207,7 @@ struct draw_llvm_variant_key
    unsigned bypass_viewport:1;
    unsigned need_edgeflags:1;
    unsigned ucp_enable:PIPE_MAX_CLIP_PLANES;
-   unsigned pad:9-PIPE_MAX_CLIP_PLANES;
+   unsigned pad:33-PIPE_MAX_CLIP_PLANES;
 
    /* Variable number of vertex elements:
     */
@@ -182,34 +215,33 @@ struct draw_llvm_variant_key
 
    /* Followed by variable number of samplers:
     */
-/*   struct lp_sampler_static_state sampler; */
+/*   struct draw_sampler_static_state sampler; */
 };
 
 #define DRAW_LLVM_MAX_VARIANT_KEY_SIZE \
    (sizeof(struct draw_llvm_variant_key) +	\
-    PIPE_MAX_SAMPLERS * sizeof(struct lp_sampler_static_state) +	\
+    PIPE_MAX_SHADER_SAMPLER_VIEWS * sizeof(struct draw_sampler_static_state) +	\
     (PIPE_MAX_ATTRIBS-1) * sizeof(struct pipe_vertex_element))
 
 
 static INLINE size_t
 draw_llvm_variant_key_size(unsigned nr_vertex_elements,
-			   unsigned nr_samplers)
+                           unsigned nr_samplers)
 {
    return (sizeof(struct draw_llvm_variant_key) +
-	   nr_samplers * sizeof(struct lp_sampler_static_state) +
-	   (nr_vertex_elements - 1) * sizeof(struct pipe_vertex_element));
+           nr_samplers * sizeof(struct draw_sampler_static_state) +
+           (nr_vertex_elements - 1) * sizeof(struct pipe_vertex_element));
 }
 
 
-static INLINE struct lp_sampler_static_state *
+static INLINE struct draw_sampler_static_state *
 draw_llvm_variant_key_samplers(struct draw_llvm_variant_key *key)
 {
-   return (struct lp_sampler_static_state *)
+   return (struct draw_sampler_static_state *)
       &key->vertex_element[key->nr_vertex_elements];
 }
 
 
-
 struct draw_llvm_variant_list_item
 {
    struct draw_llvm_variant *base;
@@ -275,8 +307,8 @@ draw_llvm_destroy(struct draw_llvm *llvm);
 
 struct draw_llvm_variant *
 draw_llvm_create_variant(struct draw_llvm *llvm,
-			 unsigned num_vertex_header_attribs,
-			 const struct draw_llvm_variant_key *key);
+                         unsigned num_vertex_header_attribs,
+                         const struct draw_llvm_variant_key *key);
 
 void
 draw_llvm_destroy_variant(struct draw_llvm_variant *variant);
@@ -288,7 +320,7 @@ void
 draw_llvm_dump_variant_key(struct draw_llvm_variant_key *key);
 
 struct lp_build_sampler_soa *
-draw_llvm_sampler_soa_create(const struct lp_sampler_static_state *static_state,
+draw_llvm_sampler_soa_create(const struct draw_sampler_static_state *static_state,
                              LLVMValueRef context_ptr);
 
 void
diff --git a/src/gallium/auxiliary/draw/draw_llvm_sample.c b/src/gallium/auxiliary/draw/draw_llvm_sample.c
index 67d4e93..593d641 100644
--- a/src/gallium/auxiliary/draw/draw_llvm_sample.c
+++ b/src/gallium/auxiliary/draw/draw_llvm_sample.c
@@ -58,7 +58,7 @@ struct draw_llvm_sampler_dynamic_state
 {
    struct lp_sampler_dynamic_state base;
 
-   const struct lp_sampler_static_state *static_state;
+   const struct draw_sampler_static_state *static_state;
 
    LLVMValueRef context_ptr;
 };
@@ -98,7 +98,7 @@ draw_llvm_texture_member(const struct lp_sampler_dynamic_state *base,
    LLVMValueRef ptr;
    LLVMValueRef res;
 
-   debug_assert(unit < PIPE_MAX_SAMPLERS);
+   debug_assert(unit < PIPE_MAX_SHADER_SAMPLER_VIEWS);
 
    /* context[0] */
    indices[0] = lp_build_const_int32(gallivm, 0);
@@ -122,6 +122,45 @@ draw_llvm_texture_member(const struct lp_sampler_dynamic_state *base,
 }
 
 
+static LLVMValueRef
+draw_llvm_sampler_member(const struct lp_sampler_dynamic_state *base,
+                         struct gallivm_state *gallivm,
+                         unsigned unit,
+                         unsigned member_index,
+                         const char *member_name,
+                         boolean emit_load)
+{
+   LLVMBuilderRef builder = gallivm->builder;
+   struct draw_llvm_sampler_dynamic_state *state =
+      (struct draw_llvm_sampler_dynamic_state *)base;
+   LLVMValueRef indices[4];
+   LLVMValueRef ptr;
+   LLVMValueRef res;
+
+   debug_assert(unit < PIPE_MAX_SAMPLERS);
+
+   /* context[0] */
+   indices[0] = lp_build_const_int32(gallivm, 0);
+   /* context[0].samplers */
+   indices[1] = lp_build_const_int32(gallivm, DRAW_JIT_CTX_SAMPLERS);
+   /* context[0].samplers[unit] */
+   indices[2] = lp_build_const_int32(gallivm, unit);
+   /* context[0].samplers[unit].member */
+   indices[3] = lp_build_const_int32(gallivm, member_index);
+
+   ptr = LLVMBuildGEP(builder, state->context_ptr, indices, Elements(indices), "");
+
+   if (emit_load)
+      res = LLVMBuildLoad(builder, ptr, "");
+   else
+      res = ptr;
+
+   lp_build_name(res, "context.sampler%u.%s", unit, member_name);
+
+   return res;
+}
+
+
 /**
  * Helper macro to instantiate the functions that generate the code to
  * fetch the members of lp_jit_texture to fulfill the sampler code
@@ -150,10 +189,23 @@ DRAW_LLVM_TEXTURE_MEMBER(base_ptr,   DRAW_JIT_TEXTURE_BASE, TRUE)
 DRAW_LLVM_TEXTURE_MEMBER(row_stride, DRAW_JIT_TEXTURE_ROW_STRIDE, FALSE)
 DRAW_LLVM_TEXTURE_MEMBER(img_stride, DRAW_JIT_TEXTURE_IMG_STRIDE, FALSE)
 DRAW_LLVM_TEXTURE_MEMBER(mip_offsets, DRAW_JIT_TEXTURE_MIP_OFFSETS, FALSE)
-DRAW_LLVM_TEXTURE_MEMBER(min_lod,    DRAW_JIT_TEXTURE_MIN_LOD, TRUE)
-DRAW_LLVM_TEXTURE_MEMBER(max_lod,    DRAW_JIT_TEXTURE_MAX_LOD, TRUE)
-DRAW_LLVM_TEXTURE_MEMBER(lod_bias,   DRAW_JIT_TEXTURE_LOD_BIAS, TRUE)
-DRAW_LLVM_TEXTURE_MEMBER(border_color, DRAW_JIT_TEXTURE_BORDER_COLOR, FALSE)
+
+
+#define DRAW_LLVM_SAMPLER_MEMBER(_name, _index, _emit_load)  \
+   static LLVMValueRef \
+   draw_llvm_sampler_##_name( const struct lp_sampler_dynamic_state *base, \
+                              struct gallivm_state *gallivm,               \
+                              unsigned unit)                            \
+   { \
+      return draw_llvm_sampler_member(base, gallivm, unit, _index, #_name, _emit_load ); \
+   }
+
+
+DRAW_LLVM_SAMPLER_MEMBER(min_lod,    DRAW_JIT_SAMPLER_MIN_LOD, TRUE)
+DRAW_LLVM_SAMPLER_MEMBER(max_lod,    DRAW_JIT_SAMPLER_MAX_LOD, TRUE)
+DRAW_LLVM_SAMPLER_MEMBER(lod_bias,   DRAW_JIT_SAMPLER_LOD_BIAS, TRUE)
+DRAW_LLVM_SAMPLER_MEMBER(border_color, DRAW_JIT_SAMPLER_BORDER_COLOR, FALSE)
+
 
 
 static void
@@ -172,7 +224,8 @@ draw_llvm_sampler_soa_emit_fetch_texel(const struct lp_build_sampler_soa *base,
                                        struct gallivm_state *gallivm,
                                        struct lp_type type,
                                        boolean is_fetch,
-                                       unsigned unit,
+                                       unsigned texture_index,
+                                       unsigned sampler_index,
                                        const LLVMValueRef *coords,
                                        const LLVMValueRef *offsets,
                                        const struct lp_derivatives *derivs,
@@ -182,14 +235,17 @@ draw_llvm_sampler_soa_emit_fetch_texel(const struct lp_build_sampler_soa *base,
 {
    struct draw_llvm_sampler_soa *sampler = (struct draw_llvm_sampler_soa *)base;
 
-   assert(unit < PIPE_MAX_SAMPLERS);
+   assert(texture_index < PIPE_MAX_SHADER_SAMPLER_VIEWS);
+   assert(sampler_index < PIPE_MAX_SAMPLERS);
 
    lp_build_sample_soa(gallivm,
-                       &sampler->dynamic_state.static_state[unit],
+                       &sampler->dynamic_state.static_state[texture_index].texture_state,
+                       &sampler->dynamic_state.static_state[sampler_index].sampler_state,
                        &sampler->dynamic_state.base,
                        type,
                        is_fetch,
-                       unit,
+                       texture_index,
+                       sampler_index,
                        coords,
                        offsets,
                        derivs,
@@ -214,7 +270,7 @@ draw_llvm_sampler_soa_emit_size_query(const struct lp_build_sampler_soa *base,
    assert(unit < PIPE_MAX_SAMPLERS);
 
    lp_build_size_query_soa(gallivm,
-                           &sampler->dynamic_state.static_state[unit],
+                           &sampler->dynamic_state.static_state[unit].texture_state,
                            &sampler->dynamic_state.base,
                            type,
                            unit,
@@ -223,7 +279,7 @@ draw_llvm_sampler_soa_emit_size_query(const struct lp_build_sampler_soa *base,
 }
 
 struct lp_build_sampler_soa *
-draw_llvm_sampler_soa_create(const struct lp_sampler_static_state *static_state,
+draw_llvm_sampler_soa_create(const struct draw_sampler_static_state *static_state,
                              LLVMValueRef context_ptr)
 {
    struct draw_llvm_sampler_soa *sampler;
@@ -244,10 +300,10 @@ draw_llvm_sampler_soa_create(const struct lp_sampler_static_state *static_state,
    sampler->dynamic_state.base.img_stride = draw_llvm_texture_img_stride;
    sampler->dynamic_state.base.base_ptr = draw_llvm_texture_base_ptr;
    sampler->dynamic_state.base.mip_offsets = draw_llvm_texture_mip_offsets;
-   sampler->dynamic_state.base.min_lod = draw_llvm_texture_min_lod;
-   sampler->dynamic_state.base.max_lod = draw_llvm_texture_max_lod;
-   sampler->dynamic_state.base.lod_bias = draw_llvm_texture_lod_bias;
-   sampler->dynamic_state.base.border_color = draw_llvm_texture_border_color;
+   sampler->dynamic_state.base.min_lod = draw_llvm_sampler_min_lod;
+   sampler->dynamic_state.base.max_lod = draw_llvm_sampler_max_lod;
+   sampler->dynamic_state.base.lod_bias = draw_llvm_sampler_lod_bias;
+   sampler->dynamic_state.base.border_color = draw_llvm_sampler_border_color;
    sampler->dynamic_state.static_state = static_state;
    sampler->dynamic_state.context_ptr = context_ptr;
 
diff --git a/src/gallium/auxiliary/draw/draw_private.h b/src/gallium/auxiliary/draw/draw_private.h
index 2223fcb..ec5791c 100644
--- a/src/gallium/auxiliary/draw/draw_private.h
+++ b/src/gallium/auxiliary/draw/draw_private.h
@@ -310,7 +310,7 @@ struct draw_context
     * we only handle vertex and geometry shaders in the draw module, but
     * there may be more in the future (ex: hull and tessellation).
     */
-   struct pipe_sampler_view *sampler_views[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS];
+   struct pipe_sampler_view *sampler_views[PIPE_SHADER_TYPES][PIPE_MAX_SHADER_SAMPLER_VIEWS];
    unsigned num_sampler_views[PIPE_SHADER_TYPES];
    const struct pipe_sampler_state *samplers[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS];
    unsigned num_samplers[PIPE_SHADER_TYPES];
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample.c b/src/gallium/auxiliary/gallivm/lp_bld_sample.c
index 04f4135..4e4bca3 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_sample.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_sample.c
@@ -87,24 +87,54 @@ lp_sampler_wrap_mode_uses_border_color(unsigned mode,
 
 
 /**
- * Initialize lp_sampler_static_state object with the gallium sampler
- * and texture state.
- * The former is considered to be static and the later dynamic.
+ * Initialize lp_sampler_static_texture_state object with the gallium
+ * texture/sampler_view state (this contains the parts which are
+ * considered static).
  */
 void
-lp_sampler_static_state(struct lp_sampler_static_state *state,
-                        const struct pipe_sampler_view *view,
-                        const struct pipe_sampler_state *sampler)
+lp_sampler_static_texture_state(struct lp_static_texture_state *state,
+                                const struct pipe_sampler_view *view)
 {
    const struct pipe_resource *texture;
 
    memset(state, 0, sizeof *state);
 
-   if (!sampler || !view || !view->texture)
+   if (!view || !view->texture)
       return;
 
    texture = view->texture;
 
+   state->format            = view->format;
+   state->swizzle_r         = view->swizzle_r;
+   state->swizzle_g         = view->swizzle_g;
+   state->swizzle_b         = view->swizzle_b;
+   state->swizzle_a         = view->swizzle_a;
+
+   state->target            = texture->target;
+   state->pot_width         = util_is_power_of_two(texture->width0);
+   state->pot_height        = util_is_power_of_two(texture->height0);
+   state->pot_depth         = util_is_power_of_two(texture->depth0);
+   state->level_zero_only   = !view->u.tex.last_level;
+
+   /*
+    * FIXME: Handle the remainder of pipe_sampler_view.
+    */
+}
+
+
+/**
+ * Initialize lp_sampler_static_sampler_state object with the gallium sampler
+ * state (this contains the parts which are considered static).
+ */
+void
+lp_sampler_static_sampler_state(struct lp_static_sampler_state *state,
+                                const struct pipe_sampler_state *sampler)
+{
+   memset(state, 0, sizeof *state);
+
+   if (!sampler)
+      return;
+
    /*
     * We don't copy sampler state over unless it is actually enabled, to avoid
     * spurious recompiles, as the sampler static state is part of the shader
@@ -117,24 +147,13 @@ lp_sampler_static_state(struct lp_sampler_static_state *state,
     * regarding 1D/2D/3D/CUBE textures, wrap modes, etc.
     */
 
-   state->format            = view->format;
-   state->swizzle_r         = view->swizzle_r;
-   state->swizzle_g         = view->swizzle_g;
-   state->swizzle_b         = view->swizzle_b;
-   state->swizzle_a         = view->swizzle_a;
-
-   state->target            = texture->target;
-   state->pot_width         = util_is_power_of_two(texture->width0);
-   state->pot_height        = util_is_power_of_two(texture->height0);
-   state->pot_depth         = util_is_power_of_two(texture->depth0);
-
    state->wrap_s            = sampler->wrap_s;
    state->wrap_t            = sampler->wrap_t;
    state->wrap_r            = sampler->wrap_r;
    state->min_img_filter    = sampler->min_img_filter;
    state->mag_img_filter    = sampler->mag_img_filter;
 
-   if (view->u.tex.last_level && sampler->max_lod > 0.0f) {
+   if (sampler->max_lod > 0.0f) {
       state->min_mip_filter = sampler->min_mip_filter;
    } else {
       state->min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
@@ -155,7 +174,11 @@ lp_sampler_static_state(struct lp_sampler_static_state *state,
             state->apply_min_lod = 1;
          }
 
-         if (sampler->max_lod < (float)view->u.tex.last_level) {
+         /*
+          * XXX this won't do anything with the mesa state tracker which always
+          * sets max_lod to not more than actually present mip maps...
+          */
+         if (sampler->max_lod < (PIPE_MAX_TEXTURE_LEVELS - 1)) {
             state->apply_max_lod = 1;
          }
       }
@@ -167,10 +190,6 @@ lp_sampler_static_state(struct lp_sampler_static_state *state,
    }
 
    state->normalized_coords = sampler->normalized_coords;
-
-   /*
-    * FIXME: Handle the remainder of pipe_sampler_view.
-    */
 }
 
 
@@ -182,7 +201,7 @@ lp_sampler_static_state(struct lp_sampler_static_state *state,
  */
 static LLVMValueRef
 lp_build_rho(struct lp_build_sample_context *bld,
-             unsigned unit,
+             unsigned texture_unit,
              const struct lp_derivatives *derivs)
 {
    struct gallivm_state *gallivm = bld->gallivm;
@@ -264,7 +283,7 @@ lp_build_rho(struct lp_build_sample_context *bld,
    rho_vec = lp_build_max(coord_bld, rho_xvec, rho_yvec);
 
    first_level = bld->dynamic_state->first_level(bld->dynamic_state,
-                                                 bld->gallivm, unit);
+                                                 bld->gallivm, texture_unit);
    first_level_vec = lp_build_broadcast_scalar(int_size_bld, first_level);
    int_size = lp_build_minify(int_size_bld, bld->int_size, first_level_vec);
    float_size = lp_build_int_to_float(float_size_bld, int_size);
@@ -489,7 +508,8 @@ lp_build_brilinear_rho(struct lp_build_context *bld,
  */
 void
 lp_build_lod_selector(struct lp_build_sample_context *bld,
-                      unsigned unit,
+                      unsigned texture_unit,
+                      unsigned sampler_unit,
                       const struct lp_derivatives *derivs,
                       LLVMValueRef lod_bias, /* optional */
                       LLVMValueRef explicit_lod, /* optional */
@@ -505,12 +525,13 @@ lp_build_lod_selector(struct lp_build_sample_context *bld,
    *out_lod_ipart = bld->perquadi_bld.zero;
    *out_lod_fpart = perquadf_bld->zero;
 
-   if (bld->static_state->min_max_lod_equal) {
+   if (bld->static_sampler_state->min_max_lod_equal) {
       /* User is forcing sampling from a particular mipmap level.
        * This is hit during mipmap generation.
        */
       LLVMValueRef min_lod =
-         bld->dynamic_state->min_lod(bld->dynamic_state, bld->gallivm, unit);
+         bld->dynamic_state->min_lod(bld->dynamic_state,
+                                     bld->gallivm, sampler_unit);
 
       lod = lp_build_broadcast_scalar(perquadf_bld, min_lod);
    }
@@ -522,16 +543,16 @@ lp_build_lod_selector(struct lp_build_sample_context *bld,
       else {
          LLVMValueRef rho;
 
-         rho = lp_build_rho(bld, unit, derivs);
+         rho = lp_build_rho(bld, texture_unit, derivs);
 
          /*
           * Compute lod = log2(rho)
           */
 
          if (!lod_bias &&
-             !bld->static_state->lod_bias_non_zero &&
-             !bld->static_state->apply_max_lod &&
-             !bld->static_state->apply_min_lod) {
+             !bld->static_sampler_state->lod_bias_non_zero &&
+             !bld->static_sampler_state->apply_max_lod &&
+             !bld->static_sampler_state->apply_min_lod) {
             /*
              * Special case when there are no post-log2 adjustments, which
              * saves instructions but keeping the integer and fractional lod
@@ -568,25 +589,28 @@ lp_build_lod_selector(struct lp_build_sample_context *bld,
       }
 
       /* add sampler lod bias */
-      if (bld->static_state->lod_bias_non_zero) {
+      if (bld->static_sampler_state->lod_bias_non_zero) {
          LLVMValueRef sampler_lod_bias =
-            bld->dynamic_state->lod_bias(bld->dynamic_state, bld->gallivm, unit);
+            bld->dynamic_state->lod_bias(bld->dynamic_state,
+                                         bld->gallivm, sampler_unit);
          sampler_lod_bias = lp_build_broadcast_scalar(perquadf_bld,
                                                       sampler_lod_bias);
          lod = LLVMBuildFAdd(builder, lod, sampler_lod_bias, "sampler_lod_bias");
       }
 
       /* clamp lod */
-      if (bld->static_state->apply_max_lod) {
+      if (bld->static_sampler_state->apply_max_lod) {
          LLVMValueRef max_lod =
-            bld->dynamic_state->max_lod(bld->dynamic_state, bld->gallivm, unit);
+            bld->dynamic_state->max_lod(bld->dynamic_state,
+                                        bld->gallivm, sampler_unit);
          max_lod = lp_build_broadcast_scalar(perquadf_bld, max_lod);
 
          lod = lp_build_min(perquadf_bld, lod, max_lod);
       }
-      if (bld->static_state->apply_min_lod) {
+      if (bld->static_sampler_state->apply_min_lod) {
          LLVMValueRef min_lod =
-            bld->dynamic_state->min_lod(bld->dynamic_state, bld->gallivm, unit);
+            bld->dynamic_state->min_lod(bld->dynamic_state,
+                                        bld->gallivm, sampler_unit);
          min_lod = lp_build_broadcast_scalar(perquadf_bld, min_lod);
 
          lod = lp_build_max(perquadf_bld, lod, min_lod);
@@ -988,9 +1012,9 @@ lp_build_mipmap_level_sizes(struct lp_build_sample_context *bld,
                                                       ilevel);
    }
    if (dims == 3 ||
-       bld->static_state->target == PIPE_TEXTURE_CUBE ||
-       bld->static_state->target == PIPE_TEXTURE_1D_ARRAY ||
-       bld->static_state->target == PIPE_TEXTURE_2D_ARRAY) {
+       bld->static_texture_state->target == PIPE_TEXTURE_CUBE ||
+       bld->static_texture_state->target == PIPE_TEXTURE_1D_ARRAY ||
+       bld->static_texture_state->target == PIPE_TEXTURE_2D_ARRAY) {
       *img_stride_vec = lp_build_get_level_stride_vec(bld,
                                                       bld->img_stride_array,
                                                       ilevel);
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample.h b/src/gallium/auxiliary/gallivm/lp_bld_sample.h
index 87bf556..a252ea2 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_sample.h
+++ b/src/gallium/auxiliary/gallivm/lp_bld_sample.h
@@ -61,12 +61,12 @@ struct lp_derivatives
 
 
 /**
- * Sampler static state.
+ * Texture static state.
  *
- * These are the bits of state from pipe_resource and pipe_sampler_state that
+ * These are the bits of state from pipe_resource/pipe_sampler_view that
  * are embedded in the generated code.
  */
-struct lp_sampler_static_state
+struct lp_static_texture_state
 {
    /* pipe_sampler_view's state */
    enum pipe_format format;
@@ -80,7 +80,24 @@ struct lp_sampler_static_state
    unsigned pot_width:1;     /**< is the width a power of two? */
    unsigned pot_height:1;
    unsigned pot_depth:1;
+   unsigned level_zero_only:1;
+};
+
+
+struct lp_derived_sampler_state
+{
+   unsigned min_mip_filter:2;
+};
+
 
+/**
+ * Sampler static state.
+ *
+ * These are the bits of state from pipe_sampler_state that
+ * are embedded in the generated code.
+ */
+struct lp_static_sampler_state
+{
    /* pipe_sampler_state's state */
    unsigned wrap_s:3;
    unsigned wrap_t:3;
@@ -105,8 +122,8 @@ struct lp_sampler_static_state
 /**
  * Sampler dynamic state.
  *
- * These are the bits of state from pipe_resource and pipe_sampler_state that
- * are computed in runtime.
+ * These are the bits of state from pipe_resource/pipe_sampler_view
+ * as well as from sampler state that are computed in runtime.
  *
  * There are obtained through callbacks, as we don't want to tie the texture
  * sampling code generation logic to any particular texture layout or pipe
@@ -114,6 +131,7 @@ struct lp_sampler_static_state
  */
 struct lp_sampler_dynamic_state
 {
+   /* First callbacks for sampler view state */
 
    /** Obtain the base texture width (returns int32) */
    LLVMValueRef
@@ -169,6 +187,8 @@ struct lp_sampler_dynamic_state
                    struct gallivm_state *gallivm,
                    unsigned unit);
 
+   /* These are callbacks for sampler state */
+
    /** Obtain texture min lod (returns float) */
    LLVMValueRef
    (*min_lod)(const struct lp_sampler_dynamic_state *state,
@@ -198,10 +218,13 @@ struct lp_build_sample_context
 {
    struct gallivm_state *gallivm;
 
-   const struct lp_sampler_static_state *static_state;
+   const struct lp_static_texture_state *static_texture_state;
+   const struct lp_static_sampler_state *static_sampler_state;
 
    struct lp_sampler_dynamic_state *dynamic_state;
 
+   struct lp_derived_sampler_state derived_sampler_state;
+
    const struct util_format_description *format_desc;
 
    /* See texture_dims() */
@@ -295,10 +318,10 @@ apply_sampler_swizzle(struct lp_build_sample_context *bld,
 {
    unsigned char swizzles[4];
 
-   swizzles[0] = bld->static_state->swizzle_r;
-   swizzles[1] = bld->static_state->swizzle_g;
-   swizzles[2] = bld->static_state->swizzle_b;
-   swizzles[3] = bld->static_state->swizzle_a;
+   swizzles[0] = bld->static_texture_state->swizzle_r;
+   swizzles[1] = bld->static_texture_state->swizzle_g;
+   swizzles[2] = bld->static_texture_state->swizzle_b;
+   swizzles[3] = bld->static_texture_state->swizzle_a;
 
    lp_build_swizzle_soa_inplace(&bld->texel_bld, texel, swizzles);
 }
@@ -338,14 +361,19 @@ lp_sampler_wrap_mode_uses_border_color(unsigned mode,
  * Derive the sampler static state.
  */
 void
-lp_sampler_static_state(struct lp_sampler_static_state *state,
-                        const struct pipe_sampler_view *view,
-                        const struct pipe_sampler_state *sampler);
+lp_sampler_static_sampler_state(struct lp_static_sampler_state *state,
+                                const struct pipe_sampler_state *sampler);
+
+
+void
+lp_sampler_static_texture_state(struct lp_static_texture_state *state,
+                                const struct pipe_sampler_view *view);
 
 
 void
 lp_build_lod_selector(struct lp_build_sample_context *bld,
-                      unsigned unit,
+                      unsigned texture_index,
+                      unsigned sampler_index,
                       const struct lp_derivatives *derivs,
                       LLVMValueRef lod_bias, /* optional */
                       LLVMValueRef explicit_lod, /* optional */
@@ -437,11 +465,13 @@ lp_build_sample_offset(struct lp_build_context *bld,
 
 void
 lp_build_sample_soa(struct gallivm_state *gallivm,
-                    const struct lp_sampler_static_state *static_state,
-                    struct lp_sampler_dynamic_state *dynamic_state,
+                    const struct lp_static_texture_state *static_texture_state,
+                    const struct lp_static_sampler_state *static_sampler_state,
+                    struct lp_sampler_dynamic_state *dynamic_texture_state,
                     struct lp_type fp_type,
                     boolean is_fetch,
-                    unsigned unit,
+                    unsigned texture_index,
+                    unsigned sampler_index,
                     const LLVMValueRef *coords,
                     const LLVMValueRef *offsets,
                     const struct lp_derivatives *derivs,
@@ -461,7 +491,7 @@ lp_build_coord_repeat_npot_linear(struct lp_build_sample_context *bld,
 
 void
 lp_build_size_query_soa(struct gallivm_state *gallivm,
-                        const struct lp_sampler_static_state *static_state,
+                        const struct lp_static_texture_state *static_state,
                         struct lp_sampler_dynamic_state *dynamic_state,
                         struct lp_type int_type,
                         unsigned unit,
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample_aos.c b/src/gallium/auxiliary/gallivm/lp_bld_sample_aos.c
index 9371e1c..616f375 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_sample_aos.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_sample_aos.c
@@ -152,7 +152,7 @@ lp_build_sample_wrap_nearest_float(struct lp_build_sample_context *bld,
       break;
    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
       length_minus_one = lp_build_sub(coord_bld, length, coord_bld->one);
-      if (bld->static_state->normalized_coords) {
+      if (bld->static_sampler_state->normalized_coords) {
          /* scale coord to length */
          coord = lp_build_mul(coord_bld, coord, length);
       }
@@ -407,7 +407,7 @@ lp_build_sample_wrap_linear_float(struct lp_build_sample_context *bld,
       }
       break;
    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
-      if (bld->static_state->normalized_coords) {
+      if (bld->static_sampler_state->normalized_coords) {
          /* mul by tex size */
          coord = lp_build_mul(coord_bld, coord, length);
       }
@@ -549,7 +549,7 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
 
    s_float = s; t_float = t; r_float = r;
 
-   if (bld->static_state->normalized_coords) {
+   if (bld->static_sampler_state->normalized_coords) {
       LLVMValueRef scaled_size;
       LLVMValueRef flt_size;
 
@@ -594,8 +594,8 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
                                     bld->format_desc->block.width,
                                     s_ipart, s_float,
                                     width_vec, x_stride,
-                                    bld->static_state->pot_width,
-                                    bld->static_state->wrap_s,
+                                    bld->static_texture_state->pot_width,
+                                    bld->static_sampler_state->wrap_s,
                                     &x_offset, &x_subcoord);
    offset = x_offset;
    if (dims >= 2) {
@@ -604,8 +604,8 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
                                        bld->format_desc->block.height,
                                        t_ipart, t_float,
                                        height_vec, row_stride_vec,
-                                       bld->static_state->pot_height,
-                                       bld->static_state->wrap_t,
+                                       bld->static_texture_state->pot_height,
+                                       bld->static_sampler_state->wrap_t,
                                        &y_offset, &y_subcoord);
       offset = lp_build_add(&bld->int_coord_bld, offset, y_offset);
       if (dims >= 3) {
@@ -614,15 +614,15 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
                                           1, /* block length (depth) */
                                           r_ipart, r_float,
                                           depth_vec, img_stride_vec,
-                                          bld->static_state->pot_depth,
-                                          bld->static_state->wrap_r,
+                                          bld->static_texture_state->pot_depth,
+                                          bld->static_sampler_state->wrap_r,
                                           &z_offset, &z_subcoord);
          offset = lp_build_add(&bld->int_coord_bld, offset, z_offset);
       }
    }
-   if (bld->static_state->target == PIPE_TEXTURE_CUBE ||
-       bld->static_state->target == PIPE_TEXTURE_1D_ARRAY ||
-       bld->static_state->target == PIPE_TEXTURE_2D_ARRAY) {
+   if (bld->static_texture_state->target == PIPE_TEXTURE_CUBE ||
+       bld->static_texture_state->target == PIPE_TEXTURE_1D_ARRAY ||
+       bld->static_texture_state->target == PIPE_TEXTURE_2D_ARRAY) {
       LLVMValueRef z_offset;
       /* The r coord is the cube face in [0,5] or array layer */
       z_offset = lp_build_mul(&bld->int_coord_bld, r, img_stride_vec);
@@ -678,28 +678,28 @@ lp_build_sample_image_nearest_afloat(struct lp_build_sample_context *bld,
    /* Do texcoord wrapping */
    lp_build_sample_wrap_nearest_float(bld,
                                       s, width_vec,
-                                      bld->static_state->pot_width,
-                                      bld->static_state->wrap_s,
+                                      bld->static_texture_state->pot_width,
+                                      bld->static_sampler_state->wrap_s,
                                       &x_icoord);
 
    if (dims >= 2) {
       lp_build_sample_wrap_nearest_float(bld,
                                          t, height_vec,
-                                         bld->static_state->pot_height,
-                                         bld->static_state->wrap_t,
+                                         bld->static_texture_state->pot_height,
+                                         bld->static_sampler_state->wrap_t,
                                          &y_icoord);
 
       if (dims >= 3) {
          lp_build_sample_wrap_nearest_float(bld,
                                             r, depth_vec,
-                                            bld->static_state->pot_depth,
-                                            bld->static_state->wrap_r,
+                                            bld->static_texture_state->pot_depth,
+                                            bld->static_sampler_state->wrap_r,
                                             &z_icoord);
       }
    }
-   if (bld->static_state->target == PIPE_TEXTURE_CUBE ||
-       bld->static_state->target == PIPE_TEXTURE_1D_ARRAY ||
-       bld->static_state->target == PIPE_TEXTURE_2D_ARRAY) {
+   if (bld->static_texture_state->target == PIPE_TEXTURE_CUBE ||
+       bld->static_texture_state->target == PIPE_TEXTURE_1D_ARRAY ||
+       bld->static_texture_state->target == PIPE_TEXTURE_2D_ARRAY) {
       z_icoord = r;
    }
 
@@ -885,7 +885,7 @@ lp_build_sample_fetch_image_linear(struct lp_build_sample_context *bld,
    /*
     * Linear interpolation with 8.8 fixed point.
     */
-   if (bld->static_state->force_nearest_s) {
+   if (bld->static_sampler_state->force_nearest_s) {
       /* special case 1-D lerp */
       packed_lo = lp_build_lerp(&h16,
                                 t_fpart_lo,
@@ -897,7 +897,7 @@ lp_build_sample_fetch_image_linear(struct lp_build_sample_context *bld,
                                 neighbors_hi[0][1][0],
                                 neighbors_hi[0][1][0]);
    }
-   else if (bld->static_state->force_nearest_t) {
+   else if (bld->static_sampler_state->force_nearest_t) {
       /* special case 1-D lerp */
       packed_lo = lp_build_lerp(&h16,
                                 s_fpart_lo,
@@ -1016,7 +1016,7 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
 
    s_float = s; t_float = t; r_float = r;
 
-   if (bld->static_state->normalized_coords) {
+   if (bld->static_sampler_state->normalized_coords) {
       LLVMValueRef scaled_size;
       LLVMValueRef flt_size;
 
@@ -1045,10 +1045,10 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
 
    /* subtract 0.5 (add -128) */
    i32_c128 = lp_build_const_int_vec(bld->gallivm, i32.type, -128);
-   if (!bld->static_state->force_nearest_s) {
+   if (!bld->static_sampler_state->force_nearest_s) {
       s = LLVMBuildAdd(builder, s, i32_c128, "");
    }
-   if (dims >= 2 && !bld->static_state->force_nearest_t) {
+   if (dims >= 2 && !bld->static_sampler_state->force_nearest_t) {
       t = LLVMBuildAdd(builder, t, i32_c128, "");
    }
    if (dims >= 3) {
@@ -1082,15 +1082,15 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
                                    bld->format_desc->block.width,
                                    s_ipart, &s_fpart, s_float,
                                    width_vec, x_stride,
-                                   bld->static_state->pot_width,
-                                   bld->static_state->wrap_s,
+                                   bld->static_texture_state->pot_width,
+                                   bld->static_sampler_state->wrap_s,
                                    &x_offset0, &x_offset1,
                                    &x_subcoord[0], &x_subcoord[1]);
 
    /* add potential cube/array/mip offsets now as they are constant per pixel */
-   if (bld->static_state->target == PIPE_TEXTURE_CUBE ||
-       bld->static_state->target == PIPE_TEXTURE_1D_ARRAY ||
-       bld->static_state->target == PIPE_TEXTURE_2D_ARRAY) {
+   if (bld->static_texture_state->target == PIPE_TEXTURE_CUBE ||
+       bld->static_texture_state->target == PIPE_TEXTURE_1D_ARRAY ||
+       bld->static_texture_state->target == PIPE_TEXTURE_2D_ARRAY) {
       LLVMValueRef z_offset;
       z_offset = lp_build_mul(&bld->int_coord_bld, r, img_stride_vec);
       /* The r coord is the cube face in [0,5] or array layer */
@@ -1114,8 +1114,8 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
                                       bld->format_desc->block.height,
                                       t_ipart, &t_fpart, t_float,
                                       height_vec, y_stride,
-                                      bld->static_state->pot_height,
-                                      bld->static_state->wrap_t,
+                                      bld->static_texture_state->pot_height,
+                                      bld->static_sampler_state->wrap_t,
                                       &y_offset0, &y_offset1,
                                       &y_subcoord[0], &y_subcoord[1]);
 
@@ -1134,8 +1134,8 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
                                       bld->format_desc->block.height,
                                       r_ipart, &r_fpart, r_float,
                                       depth_vec, z_stride,
-                                      bld->static_state->pot_depth,
-                                      bld->static_state->wrap_r,
+                                      bld->static_texture_state->pot_depth,
+                                      bld->static_sampler_state->wrap_r,
                                       &z_offset0, &z_offset1,
                                       &z_subcoord[0], &z_subcoord[1]);
       for (y = 0; y < 2; y++) {
@@ -1205,28 +1205,28 @@ lp_build_sample_image_linear_afloat(struct lp_build_sample_context *bld,
    lp_build_sample_wrap_linear_float(bld,
                                      bld->format_desc->block.width,
                                      s, width_vec,
-                                     bld->static_state->pot_width,
-                                     bld->static_state->wrap_s,
+                                     bld->static_texture_state->pot_width,
+                                     bld->static_sampler_state->wrap_s,
                                      &x_icoord0, &x_icoord1,
                                      &s_fpart,
-                                     bld->static_state->force_nearest_s);
+                                     bld->static_sampler_state->force_nearest_s);
 
    if (dims >= 2) {
       lp_build_sample_wrap_linear_float(bld,
                                         bld->format_desc->block.height,
                                         t, height_vec,
-                                        bld->static_state->pot_height,
-                                        bld->static_state->wrap_t,
+                                        bld->static_texture_state->pot_height,
+                                        bld->static_sampler_state->wrap_t,
                                         &y_icoord0, &y_icoord1,
                                         &t_fpart,
-                                        bld->static_state->force_nearest_t);
+                                        bld->static_sampler_state->force_nearest_t);
 
       if (dims >= 3) {
          lp_build_sample_wrap_linear_float(bld,
                                            bld->format_desc->block.height,
                                            r, depth_vec,
-                                           bld->static_state->pot_depth,
-                                           bld->static_state->wrap_r,
+                                           bld->static_texture_state->pot_depth,
+                                           bld->static_sampler_state->wrap_r,
                                            &z_icoord0, &z_icoord1,
                                            &r_fpart, 0);
       }
@@ -1259,9 +1259,9 @@ lp_build_sample_image_linear_afloat(struct lp_build_sample_context *bld,
                                   &x_offset1, &x_subcoord[1]);
 
    /* add potential cube/array/mip offsets now as they are constant per pixel */
-   if (bld->static_state->target == PIPE_TEXTURE_CUBE ||
-       bld->static_state->target == PIPE_TEXTURE_1D_ARRAY ||
-       bld->static_state->target == PIPE_TEXTURE_2D_ARRAY) {
+   if (bld->static_texture_state->target == PIPE_TEXTURE_CUBE ||
+       bld->static_texture_state->target == PIPE_TEXTURE_1D_ARRAY ||
+       bld->static_texture_state->target == PIPE_TEXTURE_2D_ARRAY) {
       LLVMValueRef z_offset;
       z_offset = lp_build_mul(&bld->int_coord_bld, r, img_stride_vec);
       /* The r coord is the cube face in [0,5] or array layer */
@@ -1582,20 +1582,20 @@ lp_build_sample_aos(struct lp_build_sample_context *bld,
 {
    struct lp_build_context *int_bld = &bld->int_bld;
    LLVMBuilderRef builder = bld->gallivm->builder;
-   const unsigned mip_filter = bld->static_state->min_mip_filter;
-   const unsigned min_filter = bld->static_state->min_img_filter;
-   const unsigned mag_filter = bld->static_state->mag_img_filter;
+   const unsigned mip_filter = bld->derived_sampler_state.min_mip_filter;
+   const unsigned min_filter = bld->static_sampler_state->min_img_filter;
+   const unsigned mag_filter = bld->static_sampler_state->mag_img_filter;
    const unsigned dims = bld->dims;
    LLVMValueRef packed, packed_lo, packed_hi;
    LLVMValueRef unswizzled[4];
    struct lp_build_context h16_bld;
 
    /* we only support the common/simple wrap modes at this time */
-   assert(lp_is_simple_wrap_mode(bld->static_state->wrap_s));
+   assert(lp_is_simple_wrap_mode(bld->static_sampler_state->wrap_s));
    if (dims >= 2)
-      assert(lp_is_simple_wrap_mode(bld->static_state->wrap_t));
+      assert(lp_is_simple_wrap_mode(bld->static_sampler_state->wrap_t));
    if (dims >= 3)
-      assert(lp_is_simple_wrap_mode(bld->static_state->wrap_r));
+      assert(lp_is_simple_wrap_mode(bld->static_sampler_state->wrap_r));
 
 
    /* make 16-bit fixed-pt builder context */
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c b/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c
index 918dd36..e22a1de 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c
@@ -85,7 +85,7 @@ lp_build_sample_texel_soa(struct lp_build_sample_context *bld,
                           LLVMValueRef mipoffsets,
                           LLVMValueRef texel_out[4])
 {
-   const struct lp_sampler_static_state *static_state = bld->static_state;
+   const struct lp_static_sampler_state *static_state = bld->static_sampler_state;
    const unsigned dims = bld->dims;
    struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
    LLVMBuilderRef builder = bld->gallivm->builder;
@@ -317,7 +317,7 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
       break;
 
    case PIPE_TEX_WRAP_CLAMP:
-      if (bld->static_state->normalized_coords) {
+      if (bld->static_sampler_state->normalized_coords) {
          /* scale coord to length */
          coord = lp_build_mul(coord_bld, coord, length_f);
       }
@@ -337,7 +337,7 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
          struct lp_build_context abs_coord_bld = bld->coord_bld;
          abs_coord_bld.type.sign = FALSE;
 
-         if (bld->static_state->normalized_coords) {
+         if (bld->static_sampler_state->normalized_coords) {
             /* mul by tex size */
             coord = lp_build_mul(coord_bld, coord, length_f);
          }
@@ -356,7 +356,7 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
       }
 
    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
-      if (bld->static_state->normalized_coords) {
+      if (bld->static_sampler_state->normalized_coords) {
          /* scale coord to length */
          coord = lp_build_mul(coord_bld, coord, length_f);
       }
@@ -389,7 +389,7 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
    case PIPE_TEX_WRAP_MIRROR_CLAMP:
       coord = lp_build_abs(coord_bld, coord);
 
-      if (bld->static_state->normalized_coords) {
+      if (bld->static_sampler_state->normalized_coords) {
          /* scale coord to length */
          coord = lp_build_mul(coord_bld, coord, length_f);
       }
@@ -411,7 +411,7 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
          abs_coord_bld.type.sign = FALSE;
          coord = lp_build_abs(coord_bld, coord);
 
-         if (bld->static_state->normalized_coords) {
+         if (bld->static_sampler_state->normalized_coords) {
             /* scale coord to length */
             coord = lp_build_mul(coord_bld, coord, length_f);
          }
@@ -433,7 +433,7 @@ lp_build_sample_wrap_linear(struct lp_build_sample_context *bld,
       {
          coord = lp_build_abs(coord_bld, coord);
 
-         if (bld->static_state->normalized_coords) {
+         if (bld->static_sampler_state->normalized_coords) {
             /* scale coord to length */
             coord = lp_build_mul(coord_bld, coord, length_f);
          }
@@ -500,7 +500,7 @@ lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
 
    case PIPE_TEX_WRAP_CLAMP:
    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
-      if (bld->static_state->normalized_coords) {
+      if (bld->static_sampler_state->normalized_coords) {
          /* scale coord to length */
          coord = lp_build_mul(coord_bld, coord, length_f);
       }
@@ -515,7 +515,7 @@ lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
       break;
 
    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
-      if (bld->static_state->normalized_coords) {
+      if (bld->static_sampler_state->normalized_coords) {
          /* scale coord to length */
          coord = lp_build_mul(coord_bld, coord, length_f);
       }
@@ -528,7 +528,7 @@ lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
       coord = lp_build_coord_mirror(bld, coord);
 
       /* scale coord to length */
-      assert(bld->static_state->normalized_coords);
+      assert(bld->static_sampler_state->normalized_coords);
       coord = lp_build_mul(coord_bld, coord, length_f);
 
       /* itrunc == ifloor here */
@@ -542,7 +542,7 @@ lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
       coord = lp_build_abs(coord_bld, coord);
 
-      if (bld->static_state->normalized_coords) {
+      if (bld->static_sampler_state->normalized_coords) {
          /* scale coord to length */
          coord = lp_build_mul(coord_bld, coord, length_f);
       }
@@ -557,7 +557,7 @@ lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld,
    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
       coord = lp_build_abs(coord_bld, coord);
 
-      if (bld->static_state->normalized_coords) {
+      if (bld->static_sampler_state->normalized_coords) {
          /* scale coord to length */
          coord = lp_build_mul(coord_bld, coord, length_f);
       }
@@ -620,26 +620,26 @@ lp_build_sample_image_nearest(struct lp_build_sample_context *bld,
     * Compute integer texcoords.
     */
    x = lp_build_sample_wrap_nearest(bld, s, width_vec, flt_width_vec,
-                                    bld->static_state->pot_width,
-                                    bld->static_state->wrap_s);
+                                    bld->static_texture_state->pot_width,
+                                    bld->static_sampler_state->wrap_s);
    lp_build_name(x, "tex.x.wrapped");
 
    if (dims >= 2) {
       y = lp_build_sample_wrap_nearest(bld, t, height_vec, flt_height_vec,
-                                       bld->static_state->pot_height,
-                                       bld->static_state->wrap_t);
+                                       bld->static_texture_state->pot_height,
+                                       bld->static_sampler_state->wrap_t);
       lp_build_name(y, "tex.y.wrapped");
 
       if (dims == 3) {
          z = lp_build_sample_wrap_nearest(bld, r, depth_vec, flt_depth_vec,
-                                          bld->static_state->pot_depth,
-                                          bld->static_state->wrap_r);
+                                          bld->static_texture_state->pot_depth,
+                                          bld->static_sampler_state->wrap_r);
          lp_build_name(z, "tex.z.wrapped");
       }
    }
-   if (bld->static_state->target == PIPE_TEXTURE_CUBE ||
-       bld->static_state->target == PIPE_TEXTURE_1D_ARRAY ||
-       bld->static_state->target == PIPE_TEXTURE_2D_ARRAY) {
+   if (bld->static_texture_state->target == PIPE_TEXTURE_CUBE ||
+       bld->static_texture_state->target == PIPE_TEXTURE_1D_ARRAY ||
+       bld->static_texture_state->target == PIPE_TEXTURE_2D_ARRAY) {
       z = r;
       lp_build_name(z, "tex.z.layer");
    }
@@ -703,32 +703,32 @@ lp_build_sample_image_linear(struct lp_build_sample_context *bld,
     * Compute integer texcoords.
     */
    lp_build_sample_wrap_linear(bld, s, width_vec, flt_width_vec,
-                               bld->static_state->pot_width,
-                               bld->static_state->wrap_s,
+                               bld->static_texture_state->pot_width,
+                               bld->static_sampler_state->wrap_s,
                                &x0, &x1, &s_fpart);
    lp_build_name(x0, "tex.x0.wrapped");
    lp_build_name(x1, "tex.x1.wrapped");
 
    if (dims >= 2) {
       lp_build_sample_wrap_linear(bld, t, height_vec, flt_height_vec,
-                                  bld->static_state->pot_height,
-                                  bld->static_state->wrap_t,
+                                  bld->static_texture_state->pot_height,
+                                  bld->static_sampler_state->wrap_t,
                                   &y0, &y1, &t_fpart);
       lp_build_name(y0, "tex.y0.wrapped");
       lp_build_name(y1, "tex.y1.wrapped");
 
       if (dims == 3) {
          lp_build_sample_wrap_linear(bld, r, depth_vec, flt_depth_vec,
-                                     bld->static_state->pot_depth,
-                                     bld->static_state->wrap_r,
+                                     bld->static_texture_state->pot_depth,
+                                     bld->static_sampler_state->wrap_r,
                                      &z0, &z1, &r_fpart);
          lp_build_name(z0, "tex.z0.wrapped");
          lp_build_name(z1, "tex.z1.wrapped");
       }
    }
-   if (bld->static_state->target == PIPE_TEXTURE_CUBE ||
-       bld->static_state->target == PIPE_TEXTURE_1D_ARRAY ||
-       bld->static_state->target == PIPE_TEXTURE_2D_ARRAY) {
+   if (bld->static_texture_state->target == PIPE_TEXTURE_CUBE ||
+       bld->static_texture_state->target == PIPE_TEXTURE_1D_ARRAY ||
+       bld->static_texture_state->target == PIPE_TEXTURE_2D_ARRAY) {
       z0 = z1 = r;  /* cube face or array layer */
       lp_build_name(z0, "tex.z0.layer");
       lp_build_name(z1, "tex.z1.layer");
@@ -1004,7 +1004,8 @@ lp_build_layer_coord(struct lp_build_sample_context *bld,
  */
 static void
 lp_build_sample_common(struct lp_build_sample_context *bld,
-                       unsigned unit,
+                       unsigned texture_index,
+                       unsigned sampler_index,
                        LLVMValueRef *s,
                        LLVMValueRef *t,
                        LLVMValueRef *r,
@@ -1016,10 +1017,10 @@ lp_build_sample_common(struct lp_build_sample_context *bld,
                        LLVMValueRef *ilevel0,
                        LLVMValueRef *ilevel1)
 {
-   const unsigned mip_filter = bld->static_state->min_mip_filter;
-   const unsigned min_filter = bld->static_state->min_img_filter;
-   const unsigned mag_filter = bld->static_state->mag_img_filter;
-   const unsigned target = bld->static_state->target;
+   const unsigned mip_filter = bld->derived_sampler_state.min_mip_filter;
+   const unsigned min_filter = bld->static_sampler_state->min_img_filter;
+   const unsigned mag_filter = bld->static_sampler_state->mag_img_filter;
+   const unsigned target = bld->static_texture_state->target;
    LLVMValueRef first_level;
    struct lp_derivatives face_derivs;
 
@@ -1046,11 +1047,11 @@ lp_build_sample_common(struct lp_build_sample_context *bld,
    }
    else if (target == PIPE_TEXTURE_1D_ARRAY) {
       *r = lp_build_iround(&bld->coord_bld, *t);
-      *r = lp_build_layer_coord(bld, unit, *r);
+      *r = lp_build_layer_coord(bld, texture_index, *r);
    }
    else if (target == PIPE_TEXTURE_2D_ARRAY) {
       *r = lp_build_iround(&bld->coord_bld, *r);
-      *r = lp_build_layer_coord(bld, unit, *r);
+      *r = lp_build_layer_coord(bld, texture_index, *r);
    }
 
    /*
@@ -1061,8 +1062,8 @@ lp_build_sample_common(struct lp_build_sample_context *bld,
       /* Need to compute lod either to choose mipmap levels or to
        * distinguish between minification/magnification with one mipmap level.
        */
-      lp_build_lod_selector(bld, unit, derivs,
-                            lod_bias, explicit_lod,
+      lp_build_lod_selector(bld, texture_index, sampler_index,
+                            derivs, lod_bias, explicit_lod,
                             mip_filter,
                             lod_ipart, lod_fpart);
    } else {
@@ -1085,23 +1086,23 @@ lp_build_sample_common(struct lp_build_sample_context *bld,
           * XXX should probably disable that on other llvm versions.
           */
          assert(*lod_ipart);
-         lp_build_nearest_mip_level(bld, unit, *lod_ipart, ilevel0);
+         lp_build_nearest_mip_level(bld, texture_index, *lod_ipart, ilevel0);
       }
       else {
          first_level = bld->dynamic_state->first_level(bld->dynamic_state,
-                                                       bld->gallivm, unit);
+                                                       bld->gallivm, texture_index);
          first_level = lp_build_broadcast_scalar(&bld->perquadi_bld, first_level);
          *ilevel0 = first_level;
       }
       break;
    case PIPE_TEX_MIPFILTER_NEAREST:
       assert(*lod_ipart);
-      lp_build_nearest_mip_level(bld, unit, *lod_ipart, ilevel0);
+      lp_build_nearest_mip_level(bld, texture_index, *lod_ipart, ilevel0);
       break;
    case PIPE_TEX_MIPFILTER_LINEAR:
       assert(*lod_ipart);
       assert(*lod_fpart);
-      lp_build_linear_mip_levels(bld, unit,
+      lp_build_linear_mip_levels(bld, texture_index,
                                  *lod_ipart, lod_fpart,
                                  ilevel0, ilevel1);
       break;
@@ -1127,9 +1128,9 @@ lp_build_sample_general(struct lp_build_sample_context *bld,
 {
    struct lp_build_context *int_bld = &bld->int_bld;
    LLVMBuilderRef builder = bld->gallivm->builder;
-   const unsigned mip_filter = bld->static_state->min_mip_filter;
-   const unsigned min_filter = bld->static_state->min_img_filter;
-   const unsigned mag_filter = bld->static_state->mag_img_filter;
+   const unsigned mip_filter = bld->derived_sampler_state.min_mip_filter;
+   const unsigned min_filter = bld->static_sampler_state->min_img_filter;
+   const unsigned mag_filter = bld->static_sampler_state->mag_img_filter;
    LLVMValueRef texels[4];
    unsigned chan;
 
@@ -1221,7 +1222,7 @@ lp_build_fetch_texel(struct lp_build_sample_context *bld,
    struct lp_build_context *perquadi_bld = &bld->perquadi_bld;
    struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
    unsigned dims = bld->dims, chan;
-   unsigned target = bld->static_state->target;
+   unsigned target = bld->static_texture_state->target;
    LLVMValueRef size, ilevel;
    LLVMValueRef row_stride_vec = NULL, img_stride_vec = NULL;
    LLVMValueRef x = coords[0], y = coords[1], z = coords[2];
@@ -1229,7 +1230,7 @@ lp_build_fetch_texel(struct lp_build_sample_context *bld,
    LLVMValueRef offset, out_of_bounds, out1;
 
    /* XXX just like ordinary sampling, we don't handle per-pixel lod (yet). */
-   if (explicit_lod && bld->static_state->target != PIPE_BUFFER) {
+   if (explicit_lod && bld->static_texture_state->target != PIPE_BUFFER) {
       ilevel = lp_build_pack_aos_scalars(bld->gallivm, int_coord_bld->type,
                                          perquadi_bld->type, explicit_lod, 0);
       lp_build_nearest_mip_level(bld, unit, ilevel, &ilevel);
@@ -1288,7 +1289,7 @@ lp_build_fetch_texel(struct lp_build_sample_context *bld,
                           x, y, z, row_stride_vec, img_stride_vec,
                           &offset, &i, &j);
 
-   if (bld->static_state->target != PIPE_BUFFER) {
+   if (bld->static_texture_state->target != PIPE_BUFFER) {
       offset = lp_build_add(int_coord_bld, offset,
                             lp_build_get_mip_offsets(bld, ilevel));
    }
@@ -1333,11 +1334,11 @@ lp_build_sample_compare(struct lp_build_sample_context *bld,
    LLVMValueRef res, p;
    const unsigned chan = 0;
 
-   if (bld->static_state->compare_mode == PIPE_TEX_COMPARE_NONE)
+   if (bld->static_sampler_state->compare_mode == PIPE_TEX_COMPARE_NONE)
       return;
 
-   if (bld->static_state->target == PIPE_TEXTURE_2D_ARRAY ||
-       bld->static_state->target == PIPE_TEXTURE_CUBE) {
+   if (bld->static_texture_state->target == PIPE_TEXTURE_2D_ARRAY ||
+       bld->static_texture_state->target == PIPE_TEXTURE_CUBE) {
       p = coords[3];
    }
    else {
@@ -1359,7 +1360,7 @@ lp_build_sample_compare(struct lp_build_sample_context *bld,
                       bld->coord_bld.one);
 
    /* result = (p FUNC texel) ? 1 : 0 */
-   res = lp_build_cmp(texel_bld, bld->static_state->compare_func,
+   res = lp_build_cmp(texel_bld, bld->static_sampler_state->compare_func,
                       p, texel[chan]);
    res = lp_build_select(texel_bld, res, texel_bld->one, texel_bld->zero);
 
@@ -1400,11 +1401,13 @@ lp_build_sample_nop(struct gallivm_state *gallivm,
  */
 void
 lp_build_sample_soa(struct gallivm_state *gallivm,
-                    const struct lp_sampler_static_state *static_state,
+                    const struct lp_static_texture_state *static_texture_state,
+                    const struct lp_static_sampler_state *static_sampler_state,
                     struct lp_sampler_dynamic_state *dynamic_state,
                     struct lp_type type,
                     boolean is_fetch,
-                    unsigned unit,
+                    unsigned texture_index,
+                    unsigned sampler_index,
                     const LLVMValueRef *coords,
                     const LLVMValueRef *offsets,
                     const struct lp_derivatives *derivs,
@@ -1412,10 +1415,11 @@ lp_build_sample_soa(struct gallivm_state *gallivm,
                     LLVMValueRef explicit_lod, /* optional */
                     LLVMValueRef texel_out[4])
 {
-   unsigned dims = texture_dims(static_state->target);
+   unsigned dims = texture_dims(static_texture_state->target);
    unsigned num_quads = type.length / 4;
-   unsigned mip_filter = static_state->min_mip_filter;
+   unsigned mip_filter;
    struct lp_build_sample_context bld;
+   struct lp_derived_sampler_state *derived_sampler_state;
    LLVMTypeRef i32t = LLVMInt32TypeInContext(gallivm->context);
    LLVMBuilderRef builder = gallivm->builder;
    LLVMValueRef tex_width, tex_height, tex_depth;
@@ -1424,7 +1428,7 @@ lp_build_sample_soa(struct gallivm_state *gallivm,
    LLVMValueRef r;
 
    if (0) {
-      enum pipe_format fmt = static_state->format;
+      enum pipe_format fmt = static_texture_state->format;
       debug_printf("Sample from %s\n", util_format_name(fmt));
    }
 
@@ -1433,9 +1437,10 @@ lp_build_sample_soa(struct gallivm_state *gallivm,
    /* Setup our build context */
    memset(&bld, 0, sizeof bld);
    bld.gallivm = gallivm;
-   bld.static_state = static_state;
+   bld.static_sampler_state = static_sampler_state;
+   bld.static_texture_state = static_texture_state;
    bld.dynamic_state = dynamic_state;
-   bld.format_desc = util_format_description(static_state->format);
+   bld.format_desc = util_format_description(static_texture_state->format);
    bld.dims = dims;
 
    bld.vector_width = lp_type_width(type);
@@ -1466,11 +1471,24 @@ lp_build_sample_soa(struct gallivm_state *gallivm,
       }
    }
 
+   derived_sampler_state = &bld.derived_sampler_state;
+   memset(derived_sampler_state, 0, sizeof(bld.derived_sampler_state));
+   if (!static_texture_state->level_zero_only) {
+      derived_sampler_state->min_mip_filter = static_sampler_state->min_mip_filter;
+   } else {
+      derived_sampler_state->min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
+   }
+   mip_filter = derived_sampler_state->min_mip_filter;
+
+   if (0) {
+      debug_printf("  .min_mip_filter = %u\n", derived_sampler_state->min_mip_filter);
+   }
+
    /*
     * There are other situations where at least the multiple int lods could be
     * avoided like min and max lod being equal.
     */
-   if ((is_fetch && explicit_lod && bld.static_state->target != PIPE_BUFFER) ||
+   if ((is_fetch && explicit_lod && bld.static_texture_state->target != PIPE_BUFFER) ||
        (!is_fetch && mip_filter != PIPE_TEX_MIPFILTER_NONE)) {
       bld.num_lods = num_quads;
    }
@@ -1497,13 +1515,13 @@ lp_build_sample_soa(struct gallivm_state *gallivm,
    lp_build_context_init(&bld.perquadi_bld, gallivm, bld.perquadi_type);
 
    /* Get the dynamic state */
-   tex_width = dynamic_state->width(dynamic_state, gallivm, unit);
-   tex_height = dynamic_state->height(dynamic_state, gallivm, unit);
-   tex_depth = dynamic_state->depth(dynamic_state, gallivm, unit);
-   bld.row_stride_array = dynamic_state->row_stride(dynamic_state, gallivm, unit);
-   bld.img_stride_array = dynamic_state->img_stride(dynamic_state, gallivm, unit);
-   bld.base_ptr = dynamic_state->base_ptr(dynamic_state, gallivm, unit);
-   bld.mip_offsets = dynamic_state->mip_offsets(dynamic_state, gallivm, unit);
+   tex_width = dynamic_state->width(dynamic_state, gallivm, texture_index);
+   tex_height = dynamic_state->height(dynamic_state, gallivm, texture_index);
+   tex_depth = dynamic_state->depth(dynamic_state, gallivm, texture_index);
+   bld.row_stride_array = dynamic_state->row_stride(dynamic_state, gallivm, texture_index);
+   bld.img_stride_array = dynamic_state->img_stride(dynamic_state, gallivm, texture_index);
+   bld.base_ptr = dynamic_state->base_ptr(dynamic_state, gallivm, texture_index);
+   bld.mip_offsets = dynamic_state->mip_offsets(dynamic_state, gallivm, texture_index);
    /* Note that mip_offsets is an array[level] of offsets to texture images */
 
    s = coords[0];
@@ -1536,7 +1554,7 @@ lp_build_sample_soa(struct gallivm_state *gallivm,
    }
 
    else if (is_fetch) {
-      lp_build_fetch_texel(&bld, unit, coords,
+      lp_build_fetch_texel(&bld, texture_index, coords,
                            explicit_lod, offsets,
                            texel_out);
    }
@@ -1545,22 +1563,22 @@ lp_build_sample_soa(struct gallivm_state *gallivm,
       LLVMValueRef lod_ipart = NULL, lod_fpart = NULL;
       LLVMValueRef ilevel0 = NULL, ilevel1 = NULL;
       boolean use_aos = util_format_fits_8unorm(bld.format_desc) &&
-                        lp_is_simple_wrap_mode(static_state->wrap_s) &&
-                        lp_is_simple_wrap_mode(static_state->wrap_t);
+                        lp_is_simple_wrap_mode(static_sampler_state->wrap_s) &&
+                        lp_is_simple_wrap_mode(static_sampler_state->wrap_t);
 
       if ((gallivm_debug & GALLIVM_DEBUG_PERF) &&
           !use_aos && util_format_fits_8unorm(bld.format_desc)) {
          debug_printf("%s: using floating point linear filtering for %s\n",
                       __FUNCTION__, bld.format_desc->short_name);
          debug_printf("  min_img %d  mag_img %d  mip %d  wraps %d  wrapt %d\n",
-                      static_state->min_img_filter,
-                      static_state->mag_img_filter,
-                      static_state->min_mip_filter,
-                      static_state->wrap_s,
-                      static_state->wrap_t);
+                      static_sampler_state->min_img_filter,
+                      static_sampler_state->mag_img_filter,
+                      static_sampler_state->min_mip_filter,
+                      static_sampler_state->wrap_s,
+                      static_sampler_state->wrap_t);
       }
 
-      lp_build_sample_common(&bld, unit,
+      lp_build_sample_common(&bld, texture_index, sampler_index,
                              &s, &t, &r,
                              derivs, lod_bias, explicit_lod,
                              &lod_ipart, &lod_fpart,
@@ -1586,7 +1604,7 @@ lp_build_sample_soa(struct gallivm_state *gallivm,
          }
          if (use_aos) {
             /* do sampling/filtering with fixed pt arithmetic */
-            lp_build_sample_aos(&bld, unit,
+            lp_build_sample_aos(&bld, sampler_index,
                                 s, t, r,
                                 lod_ipart, lod_fpart,
                                 ilevel0, ilevel1,
@@ -1594,7 +1612,7 @@ lp_build_sample_soa(struct gallivm_state *gallivm,
          }
 
          else {
-            lp_build_sample_general(&bld, unit,
+            lp_build_sample_general(&bld, sampler_index,
                                     s, t, r,
                                     lod_ipart, lod_fpart,
                                     ilevel0, ilevel1,
@@ -1614,7 +1632,8 @@ lp_build_sample_soa(struct gallivm_state *gallivm,
          /* Setup our build context */
          memset(&bld4, 0, sizeof bld4);
          bld4.gallivm = bld.gallivm;
-         bld4.static_state = bld.static_state;
+         bld4.static_texture_state = bld.static_texture_state;
+         bld4.static_sampler_state = bld.static_sampler_state;
          bld4.dynamic_state = bld.dynamic_state;
          bld4.format_desc = bld.format_desc;
          bld4.dims = bld.dims;
@@ -1675,7 +1694,7 @@ lp_build_sample_soa(struct gallivm_state *gallivm,
 
             if (use_aos) {
                /* do sampling/filtering with fixed pt arithmetic */
-               lp_build_sample_aos(&bld4, unit,
+               lp_build_sample_aos(&bld4, sampler_index,
                                    s4, t4, r4,
                                    lod_iparts, lod_fparts,
                                    ilevel0s, ilevel1s,
@@ -1683,7 +1702,7 @@ lp_build_sample_soa(struct gallivm_state *gallivm,
             }
 
             else {
-               lp_build_sample_general(&bld4, unit,
+               lp_build_sample_general(&bld4, sampler_index,
                                        s4, t4, r4,
                                        lod_iparts, lod_fparts,
                                        ilevel0s, ilevel1s,
@@ -1702,7 +1721,7 @@ lp_build_sample_soa(struct gallivm_state *gallivm,
       lp_build_sample_compare(&bld, coords, texel_out);
    }
 
-   if (static_state->target != PIPE_BUFFER) {
+   if (static_texture_state->target != PIPE_BUFFER) {
       apply_sampler_swizzle(&bld, texel_out);
    }
 
@@ -1721,7 +1740,7 @@ lp_build_sample_soa(struct gallivm_state *gallivm,
 
 void
 lp_build_size_query_soa(struct gallivm_state *gallivm,
-                        const struct lp_sampler_static_state *static_state,
+                        const struct lp_static_texture_state *static_state,
                         struct lp_sampler_dynamic_state *dynamic_state,
                         struct lp_type int_type,
                         unsigned unit,
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi.h b/src/gallium/auxiliary/gallivm/lp_bld_tgsi.h
index 16d2ed9..4898849 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi.h
+++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi.h
@@ -173,7 +173,8 @@ struct lp_build_sampler_soa
                         struct gallivm_state *gallivm,
                         struct lp_type type,
                         boolean is_fetch,
-                        unsigned unit,
+                        unsigned texture_index,
+                        unsigned sampler_index,
                         const LLVMValueRef *coords,
                         const LLVMValueRef *offsets,
                         const struct lp_derivatives *derivs,
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
index fbeb805..0621fb4 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
@@ -1331,7 +1331,8 @@ emit_tex( struct lp_build_tgsi_soa_context *bld,
                                   bld->bld_base.base.gallivm,
                                   bld->bld_base.base.type,
                                   FALSE,
-                                  unit, coords,
+                                  unit, unit,
+                                  coords,
                                   offsets,
                                   &derivs,
                                   lod_bias, explicit_lod,
@@ -1417,7 +1418,8 @@ emit_txf( struct lp_build_tgsi_soa_context *bld,
                                   bld->bld_base.base.gallivm,
                                   bld->bld_base.base.type,
                                   TRUE,
-                                  unit, coords,
+                                  unit, unit,
+                                  coords,
                                   offsets,
                                   &derivs,
                                   NULL, explicit_lod,
diff --git a/src/gallium/drivers/llvmpipe/lp_jit.c b/src/gallium/drivers/llvmpipe/lp_jit.c
index ea7c805..d0a7916 100644
--- a/src/gallium/drivers/llvmpipe/lp_jit.c
+++ b/src/gallium/drivers/llvmpipe/lp_jit.c
@@ -45,7 +45,7 @@ lp_jit_create_types(struct lp_fragment_shader_variant *lp)
 {
    struct gallivm_state *gallivm = lp->gallivm;
    LLVMContextRef lc = gallivm->context;
-   LLVMTypeRef texture_type;
+   LLVMTypeRef texture_type, sampler_type;
 
    /* struct lp_jit_texture */
    {
@@ -61,11 +61,6 @@ lp_jit_create_types(struct lp_fragment_shader_variant *lp)
       elem_types[LP_JIT_TEXTURE_IMG_STRIDE] =
       elem_types[LP_JIT_TEXTURE_MIP_OFFSETS] =
          LLVMArrayType(LLVMInt32TypeInContext(lc), LP_MAX_TEXTURE_LEVELS);
-      elem_types[LP_JIT_TEXTURE_MIN_LOD] =
-      elem_types[LP_JIT_TEXTURE_MAX_LOD] =
-      elem_types[LP_JIT_TEXTURE_LOD_BIAS] = LLVMFloatTypeInContext(lc);
-      elem_types[LP_JIT_TEXTURE_BORDER_COLOR] = 
-         LLVMArrayType(LLVMFloatTypeInContext(lc), 4);
 
       texture_type = LLVMStructTypeInContext(lc, elem_types,
                                              Elements(elem_types), 0);
@@ -102,21 +97,41 @@ lp_jit_create_types(struct lp_fragment_shader_variant *lp)
       LP_CHECK_MEMBER_OFFSET(struct lp_jit_texture, mip_offsets,
                              gallivm->target, texture_type,
                              LP_JIT_TEXTURE_MIP_OFFSETS);
-      LP_CHECK_MEMBER_OFFSET(struct lp_jit_texture, min_lod,
+      LP_CHECK_STRUCT_SIZE(struct lp_jit_texture,
+                           gallivm->target, texture_type);
+   }
+
+   {
+   /* struct lp_jit_sampler */
+      LLVMTypeRef elem_types[LP_JIT_SAMPLER_NUM_FIELDS];
+      elem_types[LP_JIT_SAMPLER_MIN_LOD] =
+      elem_types[LP_JIT_SAMPLER_MAX_LOD] =
+      elem_types[LP_JIT_SAMPLER_LOD_BIAS] = LLVMFloatTypeInContext(lc);
+      elem_types[LP_JIT_SAMPLER_BORDER_COLOR] =
+         LLVMArrayType(LLVMFloatTypeInContext(lc), 4);
+
+      sampler_type = LLVMStructTypeInContext(lc, elem_types,
+                                             Elements(elem_types), 0);
+#if HAVE_LLVM < 0x0300
+      LLVMAddTypeName(gallivm->module, "texture", texture_type);
+
+      LLVMInvalidateStructLayout(gallivm->target, texture_type);
+#endif
+
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_sampler, min_lod,
                              gallivm->target, texture_type,
-                             LP_JIT_TEXTURE_MIN_LOD);
-      LP_CHECK_MEMBER_OFFSET(struct lp_jit_texture, max_lod,
+                             LP_JIT_SAMPLER_MIN_LOD);
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_sampler, max_lod,
                              gallivm->target, texture_type,
-                             LP_JIT_TEXTURE_MAX_LOD);
-      LP_CHECK_MEMBER_OFFSET(struct lp_jit_texture, lod_bias,
+                             LP_JIT_SAMPLER_MAX_LOD);
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_sampler, lod_bias,
                              gallivm->target, texture_type,
-                             LP_JIT_TEXTURE_LOD_BIAS);
-      LP_CHECK_MEMBER_OFFSET(struct lp_jit_texture, border_color,
+                             LP_JIT_SAMPLER_LOD_BIAS);
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_sampler, border_color,
                              gallivm->target, texture_type,
-                             LP_JIT_TEXTURE_BORDER_COLOR);
-
-      LP_CHECK_STRUCT_SIZE(struct lp_jit_texture,
-                           gallivm->target, texture_type);
+                             LP_JIT_SAMPLER_BORDER_COLOR);
+      LP_CHECK_STRUCT_SIZE(struct lp_jit_sampler,
+                           gallivm->target, sampler_type);
    }
 
    /* struct lp_jit_context */
@@ -132,6 +147,8 @@ lp_jit_create_types(struct lp_fragment_shader_variant *lp)
       elem_types[LP_JIT_CTX_U8_BLEND_COLOR] = LLVMPointerType(LLVMInt8TypeInContext(lc), 0);
       elem_types[LP_JIT_CTX_F_BLEND_COLOR] = LLVMPointerType(LLVMFloatTypeInContext(lc), 0);
       elem_types[LP_JIT_CTX_TEXTURES] = LLVMArrayType(texture_type,
+                                                      PIPE_MAX_SHADER_SAMPLER_VIEWS);
+      elem_types[LP_JIT_CTX_SAMPLERS] = LLVMArrayType(sampler_type,
                                                       PIPE_MAX_SAMPLERS);
 
       context_type = LLVMStructTypeInContext(lc, elem_types,
@@ -164,6 +181,9 @@ lp_jit_create_types(struct lp_fragment_shader_variant *lp)
       LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, textures,
                              gallivm->target, context_type,
                              LP_JIT_CTX_TEXTURES);
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, samplers,
+                             gallivm->target, context_type,
+                             LP_JIT_CTX_SAMPLERS);
       LP_CHECK_STRUCT_SIZE(struct lp_jit_context,
                            gallivm->target, context_type);
 
diff --git a/src/gallium/drivers/llvmpipe/lp_jit.h b/src/gallium/drivers/llvmpipe/lp_jit.h
index 5dc5bc4..3057c0d 100644
--- a/src/gallium/drivers/llvmpipe/lp_jit.h
+++ b/src/gallium/drivers/llvmpipe/lp_jit.h
@@ -58,7 +58,11 @@ struct lp_jit_texture
    uint32_t row_stride[LP_MAX_TEXTURE_LEVELS];
    uint32_t img_stride[LP_MAX_TEXTURE_LEVELS];
    uint32_t mip_offsets[LP_MAX_TEXTURE_LEVELS];
-   /* sampler state, actually */
+};
+
+
+struct lp_jit_sampler
+{
    float min_lod;
    float max_lod;
    float lod_bias;
@@ -76,14 +80,18 @@ enum {
    LP_JIT_TEXTURE_ROW_STRIDE,
    LP_JIT_TEXTURE_IMG_STRIDE,
    LP_JIT_TEXTURE_MIP_OFFSETS,
-   LP_JIT_TEXTURE_MIN_LOD,
-   LP_JIT_TEXTURE_MAX_LOD,
-   LP_JIT_TEXTURE_LOD_BIAS,
-   LP_JIT_TEXTURE_BORDER_COLOR,
    LP_JIT_TEXTURE_NUM_FIELDS  /* number of fields above */
 };
 
 
+enum {
+   LP_JIT_SAMPLER_MIN_LOD,
+   LP_JIT_SAMPLER_MAX_LOD,
+   LP_JIT_SAMPLER_LOD_BIAS,
+   LP_JIT_SAMPLER_BORDER_COLOR,
+   LP_JIT_SAMPLER_NUM_FIELDS  /* number of fields above */
+};
+
 
 /**
  * This structure is passed directly to the generated fragment shader.
@@ -107,7 +115,8 @@ struct lp_jit_context
    uint8_t *u8_blend_color;
    float *f_blend_color;
 
-   struct lp_jit_texture textures[PIPE_MAX_SAMPLERS];
+   struct lp_jit_texture textures[PIPE_MAX_SHADER_SAMPLER_VIEWS];
+   struct lp_jit_sampler samplers[PIPE_MAX_SAMPLERS];
 };
 
 
@@ -123,6 +132,7 @@ enum {
    LP_JIT_CTX_U8_BLEND_COLOR,
    LP_JIT_CTX_F_BLEND_COLOR,
    LP_JIT_CTX_TEXTURES,
+   LP_JIT_CTX_SAMPLERS,
    LP_JIT_CTX_COUNT
 };
 
@@ -148,6 +158,8 @@ enum {
 #define lp_jit_context_textures(_gallivm, _ptr) \
    lp_build_struct_get_ptr(_gallivm, _ptr, LP_JIT_CTX_TEXTURES, "textures")
 
+#define lp_jit_context_samplers(_gallivm, _ptr) \
+   lp_build_struct_get_ptr(_gallivm, _ptr, LP_JIT_CTX_SAMPLERS, "samplers")
 
 
 /**
diff --git a/src/gallium/drivers/llvmpipe/lp_setup.c b/src/gallium/drivers/llvmpipe/lp_setup.c
index ffa0fe6..1eba629 100644
--- a/src/gallium/drivers/llvmpipe/lp_setup.c
+++ b/src/gallium/drivers/llvmpipe/lp_setup.c
@@ -780,13 +780,13 @@ lp_setup_set_fragment_sampler_state(struct lp_setup_context *setup,
       const struct pipe_sampler_state *sampler = i < num ? samplers[i] : NULL;
 
       if (sampler) {
-         struct lp_jit_texture *jit_tex;
-         jit_tex = &setup->fs.current.jit_context.textures[i];
+         struct lp_jit_sampler *jit_sam;
+         jit_sam = &setup->fs.current.jit_context.samplers[i];
 
-         jit_tex->min_lod = sampler->min_lod;
-         jit_tex->max_lod = sampler->max_lod;
-         jit_tex->lod_bias = sampler->lod_bias;
-         COPY_4V(jit_tex->border_color, sampler->border_color.f);
+         jit_sam->min_lod = sampler->min_lod;
+         jit_sam->max_lod = sampler->max_lod;
+         jit_sam->lod_bias = sampler->lod_bias;
+         COPY_4V(jit_sam->border_color, sampler->border_color.f);
       }
    }
 
diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.c b/src/gallium/drivers/llvmpipe/lp_state_fs.c
index cf936d0..09f37e0 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_fs.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_fs.c
@@ -1904,7 +1904,7 @@ generate_fragment(struct llvmpipe_context *lp,
    LLVMPositionBuilderAtEnd(builder, block);
 
    /* code generated texture sampling */
-   sampler = lp_llvm_sampler_soa_create(key->sampler, context_ptr);
+   sampler = lp_llvm_sampler_soa_create(key->state, context_ptr);
 
    zs_format_desc = util_format_description(key->zsbuf_format);
 
@@ -2113,32 +2113,39 @@ dump_fs_variant_key(const struct lp_fragment_shader_variant_key *key)
    }
    debug_printf("blend.colormask = 0x%x\n", key->blend.rt[0].colormask);
    for (i = 0; i < key->nr_samplers; ++i) {
+      const struct lp_static_sampler_state *sampler = &key->state[i].sampler_state;
       debug_printf("sampler[%u] = \n", i);
-      debug_printf("  .format = %s\n",
-                   util_format_name(key->sampler[i].format));
-      debug_printf("  .target = %s\n",
-                   util_dump_tex_target(key->sampler[i].target, TRUE));
-      debug_printf("  .pot = %u %u %u\n",
-                   key->sampler[i].pot_width,
-                   key->sampler[i].pot_height,
-                   key->sampler[i].pot_depth);
       debug_printf("  .wrap = %s %s %s\n",
-                   util_dump_tex_wrap(key->sampler[i].wrap_s, TRUE),
-                   util_dump_tex_wrap(key->sampler[i].wrap_t, TRUE),
-                   util_dump_tex_wrap(key->sampler[i].wrap_r, TRUE));
+                   util_dump_tex_wrap(sampler->wrap_s, TRUE),
+                   util_dump_tex_wrap(sampler->wrap_t, TRUE),
+                   util_dump_tex_wrap(sampler->wrap_r, TRUE));
       debug_printf("  .min_img_filter = %s\n",
-                   util_dump_tex_filter(key->sampler[i].min_img_filter, TRUE));
+                   util_dump_tex_filter(sampler->min_img_filter, TRUE));
       debug_printf("  .min_mip_filter = %s\n",
-                   util_dump_tex_mipfilter(key->sampler[i].min_mip_filter, TRUE));
+                   util_dump_tex_mipfilter(sampler->min_mip_filter, TRUE));
       debug_printf("  .mag_img_filter = %s\n",
-                   util_dump_tex_filter(key->sampler[i].mag_img_filter, TRUE));
-      if (key->sampler[i].compare_mode != PIPE_TEX_COMPARE_NONE)
-         debug_printf("  .compare_func = %s\n", util_dump_func(key->sampler[i].compare_func, TRUE));
-      debug_printf("  .normalized_coords = %u\n", key->sampler[i].normalized_coords);
-      debug_printf("  .min_max_lod_equal = %u\n", key->sampler[i].min_max_lod_equal);
-      debug_printf("  .lod_bias_non_zero = %u\n", key->sampler[i].lod_bias_non_zero);
-      debug_printf("  .apply_min_lod = %u\n", key->sampler[i].apply_min_lod);
-      debug_printf("  .apply_max_lod = %u\n", key->sampler[i].apply_max_lod);
+                   util_dump_tex_filter(sampler->mag_img_filter, TRUE));
+      if (sampler->compare_mode != PIPE_TEX_COMPARE_NONE)
+         debug_printf("  .compare_func = %s\n", util_dump_func(sampler->compare_func, TRUE));
+      debug_printf("  .normalized_coords = %u\n", sampler->normalized_coords);
+      debug_printf("  .min_max_lod_equal = %u\n", sampler->min_max_lod_equal);
+      debug_printf("  .lod_bias_non_zero = %u\n", sampler->lod_bias_non_zero);
+      debug_printf("  .apply_min_lod = %u\n", sampler->apply_min_lod);
+      debug_printf("  .apply_max_lod = %u\n", sampler->apply_max_lod);
+   }
+   for (i = 0; i < key->nr_sampler_views; ++i) {
+      const struct lp_static_texture_state *texture = &key->state[i].texture_state;
+      debug_printf("texture[%u] = \n", i);
+      debug_printf("  .format = %s\n",
+                   util_format_name(texture->format));
+      debug_printf("  .target = %s\n",
+                   util_dump_tex_target(texture->target, TRUE));
+      debug_printf("  .level_zero_only = %u\n",
+                   texture->level_zero_only);
+      debug_printf("  .pot = %u %u %u\n",
+                   texture->pot_width,
+                   texture->pot_height,
+                   texture->pot_depth);
    }
 }
 
@@ -2251,6 +2258,7 @@ llvmpipe_create_fs_state(struct pipe_context *pipe,
    struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
    struct lp_fragment_shader *shader;
    int nr_samplers;
+   int nr_sampler_views;
    int i;
 
    shader = CALLOC_STRUCT(lp_fragment_shader);
@@ -2274,9 +2282,10 @@ llvmpipe_create_fs_state(struct pipe_context *pipe,
    }
 
    nr_samplers = shader->info.base.file_max[TGSI_FILE_SAMPLER] + 1;
+   nr_sampler_views = shader->info.base.file_max[TGSI_FILE_SAMPLER_VIEW] + 1;
 
    shader->variant_key_size = Offset(struct lp_fragment_shader_variant_key,
-				     sampler[nr_samplers]);
+                                     state[MAX2(nr_samplers, nr_sampler_views)]);
 
    for (i = 0; i < shader->info.base.num_inputs; i++) {
       shader->inputs[i].usage_mask = shader->info.base.input_usage_mask[i];
@@ -2605,9 +2614,32 @@ make_variant_key(struct llvmpipe_context *lp,
 
    for(i = 0; i < key->nr_samplers; ++i) {
       if(shader->info.base.file_mask[TGSI_FILE_SAMPLER] & (1 << i)) {
-         lp_sampler_static_state(&key->sampler[i],
-				 lp->sampler_views[PIPE_SHADER_FRAGMENT][i],
-				 lp->samplers[PIPE_SHADER_FRAGMENT][i]);
+         lp_sampler_static_sampler_state(&key->state[i].sampler_state,
+                                         lp->samplers[PIPE_SHADER_FRAGMENT][i]);
+      }
+   }
+
+   /*
+    * XXX If TGSI_FILE_SAMPLER_VIEW exists assume all texture opcodes
+    * are dx10-style? Can't really have mixed opcodes, at least not
+    * if we want to skip the holes here (without rescanning tgsi).
+    */
+   if (shader->info.base.file_max[TGSI_FILE_SAMPLER_VIEW] != -1) {
+      key->nr_sampler_views = shader->info.base.file_max[TGSI_FILE_SAMPLER_VIEW] + 1;
+      for(i = 0; i < key->nr_sampler_views; ++i) {
+         if(shader->info.base.file_mask[TGSI_FILE_SAMPLER_VIEW] & (1 << i)) {
+            lp_sampler_static_texture_state(&key->state[i].texture_state,
+                                            lp->sampler_views[PIPE_SHADER_FRAGMENT][i]);
+         }
+      }
+   }
+   else {
+      key->nr_sampler_views = key->nr_samplers;
+      for(i = 0; i < key->nr_sampler_views; ++i) {
+         if(shader->info.base.file_mask[TGSI_FILE_SAMPLER] & (1 << i)) {
+            lp_sampler_static_texture_state(&key->state[i].texture_state,
+                                            lp->sampler_views[PIPE_SHADER_FRAGMENT][i]);
+         }
       }
    }
 }
diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.h b/src/gallium/drivers/llvmpipe/lp_state_fs.h
index 306f5f9..dbe657c 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_fs.h
+++ b/src/gallium/drivers/llvmpipe/lp_state_fs.h
@@ -46,6 +46,18 @@ struct lp_fragment_shader;
 #define RAST_WHOLE 0
 #define RAST_EDGE_TEST 1
 
+struct lp_sampler_static_state
+{
+   /*
+    * These attributes are effectively interleaved for more sane key handling.
+    * However, there might be lots of null space if the amount of samplers and
+    * textures isn't the same.
+    */
+   struct lp_static_sampler_state sampler_state;
+   struct lp_static_texture_state texture_state;
+};
+
+
 
 struct lp_fragment_shader_variant_key
 {
@@ -59,14 +71,15 @@ struct lp_fragment_shader_variant_key
    } alpha;
 
    unsigned nr_cbufs:8;
-   unsigned nr_samplers:8;	/* actually derivable from just the shader */
+   unsigned nr_samplers:8;      /* actually derivable from just the shader */
+   unsigned nr_sampler_views:8; /* actually derivable from just the shader */
    unsigned flatshade:1;
    unsigned occlusion_count:1;
 
    enum pipe_format zsbuf_format;
    enum pipe_format cbuf_format[PIPE_MAX_COLOR_BUFS];
 
-   struct lp_sampler_static_state sampler[PIPE_MAX_SAMPLERS];
+   struct lp_sampler_static_state state[PIPE_MAX_SHADER_SAMPLER_VIEWS];
 };
 
 
diff --git a/src/gallium/drivers/llvmpipe/lp_state_setup.c b/src/gallium/drivers/llvmpipe/lp_state_setup.c
index f44eed4..9dd337a 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_setup.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_setup.c
@@ -795,19 +795,19 @@ fail:
 
 static void
 lp_make_setup_variant_key(struct llvmpipe_context *lp,
-			  struct lp_setup_variant_key *key)
+                          struct lp_setup_variant_key *key)
 {
    struct lp_fragment_shader *fs = lp->fs;
    unsigned i;
 
    assert(sizeof key->inputs[0] == sizeof(uint));
-   
+
    key->num_inputs = fs->info.base.num_inputs;
    key->flatshade_first = lp->rasterizer->flatshade_first;
    key->pixel_center_half = lp->rasterizer->gl_rasterization_rules;
    key->twoside = lp->rasterizer->light_twoside;
    key->size = Offset(struct lp_setup_variant_key,
-		      inputs[key->num_inputs]);
+                      inputs[key->num_inputs]);
 
    key->color_slot  = lp->color_slot [0];
    key->bcolor_slot = lp->bcolor_slot[0];
@@ -825,9 +825,9 @@ lp_make_setup_variant_key(struct llvmpipe_context *lp,
    for (i = 0; i < key->num_inputs; i++) {
       if (key->inputs[i].interp == LP_INTERP_COLOR) {
          if (lp->rasterizer->flatshade)
-	    key->inputs[i].interp = LP_INTERP_CONSTANT;
-	 else
-	    key->inputs[i].interp = LP_INTERP_PERSPECTIVE;
+            key->inputs[i].interp = LP_INTERP_CONSTANT;
+         else
+            key->inputs[i].interp = LP_INTERP_PERSPECTIVE;
       }
    }
 
@@ -836,11 +836,11 @@ lp_make_setup_variant_key(struct llvmpipe_context *lp,
 
 static void
 remove_setup_variant(struct llvmpipe_context *lp,
-		     struct lp_setup_variant *variant)
+                     struct lp_setup_variant *variant)
 {
    if (gallivm_debug & GALLIVM_DEBUG_IR) {
       debug_printf("llvmpipe: del setup_variant #%u total %u\n",
-		   variant->no, lp->nr_setup_variants);
+                   variant->no, lp->nr_setup_variants);
    }
 
    if (variant->function) {
diff --git a/src/gallium/drivers/llvmpipe/lp_tex_sample.c b/src/gallium/drivers/llvmpipe/lp_tex_sample.c
index 0bd5c4a..25125a0 100644
--- a/src/gallium/drivers/llvmpipe/lp_tex_sample.c
+++ b/src/gallium/drivers/llvmpipe/lp_tex_sample.c
@@ -49,6 +49,7 @@
 #include "gallivm/lp_bld_tgsi.h"
 #include "lp_jit.h"
 #include "lp_tex_sample.h"
+#include "lp_state_fs.h"
 #include "lp_debug.h"
 
 
@@ -103,7 +104,7 @@ lp_llvm_texture_member(const struct lp_sampler_dynamic_state *base,
    LLVMValueRef ptr;
    LLVMValueRef res;
 
-   assert(unit < PIPE_MAX_SAMPLERS);
+   assert(unit < PIPE_MAX_SHADER_SAMPLER_VIEWS);
 
    /* context[0] */
    indices[0] = lp_build_const_int32(gallivm, 0);
@@ -155,10 +156,69 @@ LP_LLVM_TEXTURE_MEMBER(base_ptr,   LP_JIT_TEXTURE_BASE, TRUE)
 LP_LLVM_TEXTURE_MEMBER(row_stride, LP_JIT_TEXTURE_ROW_STRIDE, FALSE)
 LP_LLVM_TEXTURE_MEMBER(img_stride, LP_JIT_TEXTURE_IMG_STRIDE, FALSE)
 LP_LLVM_TEXTURE_MEMBER(mip_offsets, LP_JIT_TEXTURE_MIP_OFFSETS, FALSE)
-LP_LLVM_TEXTURE_MEMBER(min_lod,    LP_JIT_TEXTURE_MIN_LOD, TRUE)
-LP_LLVM_TEXTURE_MEMBER(max_lod,    LP_JIT_TEXTURE_MAX_LOD, TRUE)
-LP_LLVM_TEXTURE_MEMBER(lod_bias,   LP_JIT_TEXTURE_LOD_BIAS, TRUE)
-LP_LLVM_TEXTURE_MEMBER(border_color, LP_JIT_TEXTURE_BORDER_COLOR, FALSE)
+
+
+/**
+ * Fetch the specified member of the lp_jit_sampler structure.
+ * \param emit_load  if TRUE, emit the LLVM load instruction to actually
+ *                   fetch the field's value.  Otherwise, just emit the
+ *                   GEP code to address the field.
+ *
+ * @sa http://llvm.org/docs/GetElementPtr.html
+ */
+static LLVMValueRef
+lp_llvm_sampler_member(const struct lp_sampler_dynamic_state *base,
+                       struct gallivm_state *gallivm,
+                       unsigned unit,
+                       unsigned member_index,
+                       const char *member_name,
+                       boolean emit_load)
+{
+   struct llvmpipe_sampler_dynamic_state *state =
+      (struct llvmpipe_sampler_dynamic_state *)base;
+   LLVMBuilderRef builder = gallivm->builder;
+   LLVMValueRef indices[4];
+   LLVMValueRef ptr;
+   LLVMValueRef res;
+
+   assert(unit < PIPE_MAX_SAMPLERS);
+
+   /* context[0] */
+   indices[0] = lp_build_const_int32(gallivm, 0);
+   /* context[0].samplers */
+   indices[1] = lp_build_const_int32(gallivm, LP_JIT_CTX_SAMPLERS);
+   /* context[0].samplers[unit] */
+   indices[2] = lp_build_const_int32(gallivm, unit);
+   /* context[0].samplers[unit].member */
+   indices[3] = lp_build_const_int32(gallivm, member_index);
+
+   ptr = LLVMBuildGEP(builder, state->context_ptr, indices, Elements(indices), "");
+
+   if (emit_load)
+      res = LLVMBuildLoad(builder, ptr, "");
+   else
+      res = ptr;
+
+   lp_build_name(res, "context.sampler%u.%s", unit, member_name);
+
+   return res;
+}
+
+
+#define LP_LLVM_SAMPLER_MEMBER(_name, _index, _emit_load)  \
+   static LLVMValueRef \
+   lp_llvm_sampler_##_name( const struct lp_sampler_dynamic_state *base, \
+                            struct gallivm_state *gallivm, \
+                            unsigned unit) \
+   { \
+      return lp_llvm_sampler_member(base, gallivm, unit, _index, #_name, _emit_load ); \
+   }
+
+
+LP_LLVM_SAMPLER_MEMBER(min_lod,    LP_JIT_SAMPLER_MIN_LOD, TRUE)
+LP_LLVM_SAMPLER_MEMBER(max_lod,    LP_JIT_SAMPLER_MAX_LOD, TRUE)
+LP_LLVM_SAMPLER_MEMBER(lod_bias,   LP_JIT_SAMPLER_LOD_BIAS, TRUE)
+LP_LLVM_SAMPLER_MEMBER(border_color, LP_JIT_SAMPLER_BORDER_COLOR, FALSE)
 
 
 static void
@@ -177,7 +237,8 @@ lp_llvm_sampler_soa_emit_fetch_texel(const struct lp_build_sampler_soa *base,
                                      struct gallivm_state *gallivm,
                                      struct lp_type type,
                                      boolean is_fetch,
-                                     unsigned unit,
+                                     unsigned texture_index,
+                                     unsigned sampler_index,
                                      const LLVMValueRef *coords,
                                      const LLVMValueRef *offsets,
                                      const struct lp_derivatives *derivs,
@@ -187,7 +248,8 @@ lp_llvm_sampler_soa_emit_fetch_texel(const struct lp_build_sampler_soa *base,
 {
    struct lp_llvm_sampler_soa *sampler = (struct lp_llvm_sampler_soa *)base;
 
-   assert(unit < PIPE_MAX_SAMPLERS);
+   assert(sampler_index < PIPE_MAX_SAMPLERS);
+   assert(texture_index < PIPE_MAX_SHADER_SAMPLER_VIEWS);
    
    if (LP_PERF & PERF_NO_TEX) {
       lp_build_sample_nop(gallivm, type, coords, texel);
@@ -195,11 +257,13 @@ lp_llvm_sampler_soa_emit_fetch_texel(const struct lp_build_sampler_soa *base,
    }
 
    lp_build_sample_soa(gallivm,
-                       &sampler->dynamic_state.static_state[unit],
+                       &sampler->dynamic_state.static_state[texture_index].texture_state,
+                       &sampler->dynamic_state.static_state[sampler_index].sampler_state,
                        &sampler->dynamic_state.base,
                        type,
                        is_fetch,
-                       unit,
+                       texture_index,
+                       sampler_index,
                        coords,
                        offsets,
                        derivs,
@@ -221,14 +285,14 @@ lp_llvm_sampler_soa_emit_size_query(const struct lp_build_sampler_soa *base,
    struct lp_llvm_sampler_soa *sampler = (struct lp_llvm_sampler_soa *)base;
 
    assert(unit < PIPE_MAX_SAMPLERS);
-   
+
    lp_build_size_query_soa(gallivm,
-			   &sampler->dynamic_state.static_state[unit],
-			   &sampler->dynamic_state.base,
+                           &sampler->dynamic_state.static_state[unit].texture_state,
+                           &sampler->dynamic_state.base,
                            type,
-			   unit,
-			   explicit_lod,
-			   sizes_out);
+                           unit,
+                           explicit_lod,
+                           sizes_out);
 }
 
 
@@ -254,10 +318,10 @@ lp_llvm_sampler_soa_create(const struct lp_sampler_static_state *static_state,
    sampler->dynamic_state.base.row_stride = lp_llvm_texture_row_stride;
    sampler->dynamic_state.base.img_stride = lp_llvm_texture_img_stride;
    sampler->dynamic_state.base.mip_offsets = lp_llvm_texture_mip_offsets;
-   sampler->dynamic_state.base.min_lod = lp_llvm_texture_min_lod;
-   sampler->dynamic_state.base.max_lod = lp_llvm_texture_max_lod;
-   sampler->dynamic_state.base.lod_bias = lp_llvm_texture_lod_bias;
-   sampler->dynamic_state.base.border_color = lp_llvm_texture_border_color;
+   sampler->dynamic_state.base.min_lod = lp_llvm_sampler_min_lod;
+   sampler->dynamic_state.base.max_lod = lp_llvm_sampler_max_lod;
+   sampler->dynamic_state.base.lod_bias = lp_llvm_sampler_lod_bias;
+   sampler->dynamic_state.base.border_color = lp_llvm_sampler_border_color;
 
    sampler->dynamic_state.static_state = static_state;
    sampler->dynamic_state.context_ptr = context_ptr;
-- 
1.7.9.5



More information about the mesa-dev mailing list