Merge branch 'tex-tilecache' into softpipe-opt
authorKeith Whitwell <keithw@vmware.com>
Sun, 23 Aug 2009 09:23:46 +0000 (10:23 +0100)
committerKeith Whitwell <keithw@vmware.com>
Sun, 23 Aug 2009 09:23:46 +0000 (10:23 +0100)
Conflicts:
src/gallium/drivers/softpipe/sp_state_derived.c
src/gallium/drivers/softpipe/sp_state_sampler.c
src/gallium/drivers/softpipe/sp_tex_sample.c
src/gallium/drivers/softpipe/sp_tex_sample.h
src/gallium/drivers/softpipe/sp_tile_cache.c

1  2 
src/gallium/drivers/softpipe/sp_context.c
src/gallium/drivers/softpipe/sp_context.h
src/gallium/drivers/softpipe/sp_state_derived.c
src/gallium/drivers/softpipe/sp_state_sampler.c
src/gallium/drivers/softpipe/sp_tex_sample.c
src/gallium/drivers/softpipe/sp_tex_sample.h
src/gallium/drivers/softpipe/sp_tex_tile_cache.c
src/gallium/drivers/softpipe/sp_tile_cache.c
src/gallium/drivers/softpipe/sp_tile_cache.h

index ef8faab3bd8e819071f1de1b331db887997a0a3d,396d4c6557aa33ec3a20e748b872e906da7f6b26..48ec540ebfd0a1ccf8d762529d54a17f40850a6c
@@@ -97,7 -97,7 +97,7 @@@ static void softpipe_destroy( struct pi
     sp_destroy_tile_cache(softpipe->zsbuf_cache);
  
     for (i = 0; i < PIPE_MAX_SAMPLERS; i++)
-       sp_destroy_tile_cache(softpipe->tex_cache[i]);
+       sp_destroy_tex_tile_cache(softpipe->tex_cache[i]);
  
     for (i = 0; i < Elements(softpipe->constants); i++) {
        if (softpipe->constants[i].buffer) {
@@@ -220,7 -220,7 +220,7 @@@ softpipe_create( struct pipe_screen *sc
     softpipe->zsbuf_cache = sp_create_tile_cache( screen );
  
     for (i = 0; i < PIPE_MAX_SAMPLERS; i++)
-       softpipe->tex_cache[i] = sp_create_tile_cache( screen );
+       softpipe->tex_cache[i] = sp_create_tex_tile_cache( screen );
  
  
     /* setup quad rendering stages */
        softpipe->quad.depth_test = sp_quad_depth_test_stage(softpipe);
        softpipe->quad.blend = sp_quad_blend_stage(softpipe);
  
 -   /* vertex shader samplers */
 -   for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
 -      softpipe->tgsi.vert_samplers[i].base.get_samples = sp_get_samples_vertex;
 -      softpipe->tgsi.vert_samplers[i].cache = softpipe->tex_cache[i];
 -      softpipe->tgsi.vert_samplers_list[i] = &softpipe->tgsi.vert_samplers[i];
 -   }
 -
 -   /* fragment shader samplers */
 -   for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
 -      softpipe->tgsi.frag_samplers[i].base.get_samples = sp_get_samples_fragment;
 -      softpipe->tgsi.frag_samplers[i].cache = softpipe->tex_cache[i];
 -      softpipe->tgsi.frag_samplers_list[i] = &softpipe->tgsi.frag_samplers[i];
 -   }
  
     /*
      * Create drawing context and plug our rendering stage into it.
index 068a892f2502a95a4dc8b53d4dda1be761f1da28,683c3aef9b6882930fa52107b61edf2a4434667c..df45d2249fcd7254eab1a49211e47857265e4349
  #include "draw/draw_vertex.h"
  
  #include "sp_quad_pipe.h"
 -#include "sp_tex_sample.h"
  
  
  struct softpipe_vbuf_render;
  struct draw_context;
  struct draw_stage;
  struct softpipe_tile_cache;
+ struct softpipe_tex_tile_cache;
  struct sp_fragment_shader;
  struct sp_vertex_shader;
  
@@@ -50,12 -52,12 +51,12 @@@ struct softpipe_context 
     struct pipe_context pipe;  /**< base class */
  
     /** Constant state objects */
 -   const struct pipe_blend_state *blend;
 -   const struct pipe_sampler_state *sampler[PIPE_MAX_SAMPLERS];
 -   const struct pipe_depth_stencil_alpha_state *depth_stencil;
 -   const struct pipe_rasterizer_state *rasterizer;
 -   const struct sp_fragment_shader *fs;
 -   const struct sp_vertex_shader *vs;
 +   struct pipe_blend_state *blend;
 +   struct pipe_sampler_state *sampler[PIPE_MAX_SAMPLERS];
 +   struct pipe_depth_stencil_alpha_state *depth_stencil;
 +   struct pipe_rasterizer_state *rasterizer;
 +   struct sp_fragment_shader *fs;
 +   struct sp_vertex_shader *vs;
  
     /** Other rendering state */
     struct pipe_blend_color blend_color;
  
     /** TGSI exec things */
     struct {
 -      struct sp_shader_sampler vert_samplers[PIPE_MAX_SAMPLERS];
 -      struct sp_shader_sampler *vert_samplers_list[PIPE_MAX_SAMPLERS];
 -      struct sp_shader_sampler frag_samplers[PIPE_MAX_SAMPLERS];
 -      struct sp_shader_sampler *frag_samplers_list[PIPE_MAX_SAMPLERS];
 +      struct sp_sampler_varient *vert_samplers_list[PIPE_MAX_SAMPLERS];
 +      struct sp_sampler_varient *frag_samplers_list[PIPE_MAX_SAMPLERS];
     } tgsi;
  
     /** The primitive drawing context */
     struct softpipe_tile_cache *zsbuf_cache;
     
     unsigned tex_timestamp;
-    struct softpipe_tile_cache *tex_cache[PIPE_MAX_SAMPLERS];
+    struct softpipe_tex_tile_cache *tex_cache[PIPE_MAX_SAMPLERS];
  
     unsigned use_sse : 1;
     unsigned dump_fs : 1;
@@@ -152,9 -156,5 +153,9 @@@ softpipe_context( struct pipe_context *
     return (struct softpipe_context *)pipe;
  }
  
 +void
 +softpipe_reset_sampler_varients(struct softpipe_context *softpipe);
 +
 +
  #endif /* SP_CONTEXT_H */
  
index 202a2bc94c8cf8891e19dbf397999ae0d332d8ec,88a6e4fbdfa9045ae4682a3ecb16fccf16d4026d..04fc125e3d354a6b339967c6193dee2350629962
@@@ -34,8 -34,6 +34,8 @@@
  #include "sp_context.h"
  #include "sp_screen.h"
  #include "sp_state.h"
- #include "sp_tile_cache.h"
 +#include "sp_texture.h"
++#include "sp_tex_tile_cache.h"
  
  
  /**
@@@ -200,22 -198,24 +200,22 @@@ update_tgsi_samplers( struct softpipe_c
  {
     unsigned i;
  
 -   /* vertex shader samplers */
 -   for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
 -      softpipe->tgsi.vert_samplers[i].sampler = softpipe->sampler[i];
 -      softpipe->tgsi.vert_samplers[i].texture = softpipe->texture[i];
 -   }
 -
 -   /* fragment shader samplers */
 -   for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
 -      softpipe->tgsi.frag_samplers[i].sampler = softpipe->sampler[i];
 -      softpipe->tgsi.frag_samplers[i].texture = softpipe->texture[i];
 -      softpipe->tgsi.frag_samplers[i].base.get_samples = sp_get_samples_fragment;
 -   }
 +   softpipe_reset_sampler_varients( softpipe );
  
     for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
-       struct softpipe_tile_cache *tc = softpipe->tex_cache[i];
 -      sp_tex_tile_cache_validate_texture( softpipe->tex_cache[i] );
++      struct softpipe_tex_tile_cache *tc = softpipe->tex_cache[i];
 +      if (tc->texture) {
 +         struct softpipe_texture *spt = softpipe_texture(tc->texture);
 +         if (spt->timestamp != tc->timestamp) {
-             sp_tile_cache_validate_texture( tc );
++          sp_tex_tile_cache_validate_texture( tc );
 +            _debug_printf("INV %d %d\n", tc->timestamp, spt->timestamp);
 +            tc->timestamp = spt->timestamp;
 +         }
 +      }
     }
  }
  
 +
  /* Hopefully this will remain quite simple, otherwise need to pull in
   * something like the state tracker mechanism.
   */
@@@ -231,9 -231,7 +231,9 @@@ void softpipe_update_derived( struct so
     }
        
     if (softpipe->dirty & (SP_NEW_SAMPLER |
 -                          SP_NEW_TEXTURE))
 +                          SP_NEW_TEXTURE |
 +                          SP_NEW_FS | 
 +                          SP_NEW_VS))
        update_tgsi_samplers( softpipe );
  
     if (softpipe->dirty & (SP_NEW_RASTERIZER |
index afc6e1d2eb7623aa691f611016bf4ca831943a29,a725925264a4183ac7cf63b6c42401b1ad541ad4..db0b8ab76b1722a039b99cb779cf956f927c4e78
  
  #include "util/u_memory.h"
  
 +#include "draw/draw_context.h"
  #include "draw/draw_context.h"
  
 -#include "sp_context.h"
  #include "sp_context.h"
  #include "sp_state.h"
  #include "sp_texture.h"
- #include "sp_tile_cache.h"
 +#include "sp_tex_sample.h"
+ #include "sp_tex_tile_cache.h"
 -#include "draw/draw_context.h"
  
  
 +struct sp_sampler {
 +   struct pipe_sampler_state base;
 +   struct sp_sampler_varient *varients;
 +   struct sp_sampler_varient *current;
 +};
 +
 +static struct sp_sampler *sp_sampler( struct pipe_sampler_state *sampler )
 +{
 +   return (struct sp_sampler *)sampler;
 +}
 +
  
  void *
  softpipe_create_sampler_state(struct pipe_context *pipe,
                                const struct pipe_sampler_state *sampler)
  {
 -   return mem_dup(sampler, sizeof(*sampler));
 +   struct sp_sampler *sp_sampler = CALLOC_STRUCT(sp_sampler);
 +
 +   sp_sampler->base = *sampler;
 +   sp_sampler->varients = NULL;
 +
 +   return (void *)sp_sampler;
  }
  
  
@@@ -113,7 -97,7 +113,7 @@@ softpipe_set_sampler_textures(struct pi
        struct pipe_texture *tex = i < num ? texture[i] : NULL;
  
        pipe_texture_reference(&softpipe->texture[i], tex);
-       sp_tile_cache_set_texture(softpipe->tex_cache[i], tex);
+       sp_tex_tile_cache_set_texture(softpipe->tex_cache[i], tex);
     }
  
     softpipe->num_textures = num;
  }
  
  
 +/**
 + * Find/create an sp_sampler_varient object for sampling the given texture,
 + * sampler and tex unit.
 + *
 + * Note that the tex unit is significant.  We can't re-use a sampler
 + * varient for multiple texture units because the sampler varient contains
 + * the texture object pointer.  If the texture object pointer were stored
 + * somewhere outside the sampler varient, we could re-use samplers for
 + * multiple texture units.
 + */
 +static struct sp_sampler_varient *
 +get_sampler_varient( unsigned unit,
 +                     struct sp_sampler *sampler,
 +                     struct pipe_texture *texture,
 +                     unsigned processor )
 +{
 +   struct softpipe_texture *sp_texture = softpipe_texture(texture);
 +   struct sp_sampler_varient *v = NULL;
 +   union sp_sampler_key key;
 +
 +   /* if this fails, widen the key.unit field and update this assertion */
 +   assert(PIPE_MAX_SAMPLERS <= 16);
 +
 +   key.bits.target = sp_texture->base.target;
 +   key.bits.is_pot = sp_texture->pot;
 +   key.bits.processor = processor;
 +   key.bits.unit = unit;
 +   key.bits.pad = 0;
 +
 +   if (sampler->current && 
 +       key.value == sampler->current->key.value) {
 +      v = sampler->current;
 +   }
 +
 +   if (v == NULL) {
 +      for (v = sampler->varients; v; v = v->next)
 +         if (v->key.value == key.value)
 +            break;
 +
 +      if (v == NULL) {
 +         v = sp_create_sampler_varient( &sampler->base, key );
 +         v->next = sampler->varients;
 +         sampler->varients = v;
 +      }
 +   }
 +   
 +   sampler->current = v;
 +   return v;
 +}
 +
 +
 +
 +
 +void
 +softpipe_reset_sampler_varients(struct softpipe_context *softpipe)
 +{
 +   int i;
 +
 +   /* It's a bit hard to build these samplers ahead of time -- don't
 +    * really know which samplers are going to be used for vertex and
 +    * fragment programs.
 +    */
 +   for (i = 0; i <= softpipe->vs->max_sampler; i++) {
 +      if (softpipe->sampler[i]) {
 +         softpipe->tgsi.vert_samplers_list[i] = 
 +            get_sampler_varient( i,
 +                                 sp_sampler(softpipe->sampler[i]),
 +                                 softpipe->texture[i],
 +                                 TGSI_PROCESSOR_VERTEX );
 +
 +         sp_sampler_varient_bind_texture( softpipe->tgsi.vert_samplers_list[i], 
 +                                          softpipe->tex_cache[i],
 +                                          softpipe->texture[i] );
 +      }
 +   }
 +
 +   for (i = 0; i <= softpipe->fs->info.file_max[TGSI_FILE_SAMPLER]; i++) {
 +      if (softpipe->sampler[i]) {
 +         softpipe->tgsi.frag_samplers_list[i] =
 +            get_sampler_varient( i,
 +                                 sp_sampler(softpipe->sampler[i]),
 +                                 softpipe->texture[i],
 +                                 TGSI_PROCESSOR_FRAGMENT );
 +
 +         sp_sampler_varient_bind_texture( softpipe->tgsi.frag_samplers_list[i], 
 +                                          softpipe->tex_cache[i],
 +                                          softpipe->texture[i] );
 +      }
 +   }
 +}
 +
 +
 +
  void
  softpipe_delete_sampler_state(struct pipe_context *pipe,
                                void *sampler)
  {
 +   struct sp_sampler *sp_sampler = (struct sp_sampler *)sampler;
 +   struct sp_sampler_varient *v, *tmp;
 +
 +   for (v = sp_sampler->varients; v; v = tmp) {
 +      tmp = v->next;
 +      sp_sampler_varient_destroy(v);
 +   }
 +
     FREE( sampler );
  }
  
index a9efb82491bcca353ee12105e3dfb4456ebae05e,8bed573e8c1273d832e7cb1ede97fa309b9b8ea3..d233924565f4582a8652c14b8b8649a9fd8d149d
   *
   * Authors:
   *   Brian Paul
 + *   Keith Whitwell
   */
  
 -#include "sp_context.h"
 -#include "sp_quad.h"
 -#include "sp_surface.h"
 -#include "sp_texture.h"
 -#include "sp_tex_sample.h"
 -#include "sp_tex_tile_cache.h"
  #include "pipe/p_context.h"
  #include "pipe/p_defines.h"
 +#include "pipe/p_shader_tokens.h"
  #include "util/u_math.h"
  #include "util/u_memory.h"
- #include "sp_tile_cache.h"
 +#include "sp_quad.h"   /* only for #define QUAD_* tokens */
 +#include "sp_tex_sample.h"
++#include "sp_tex_tile_cache.h"
  
  
  
@@@ -114,157 -115,133 +114,157 @@@ lerp_3d(float a, float b, float c
   * \param icoord  returns the integer texcoords
   * \return  integer texture index
   */
 -static INLINE void
 -nearest_texcoord_4(unsigned wrapMode, const float s[4], unsigned size,
 +static void
 +wrap_nearest_repeat(const float s[4], unsigned size,
 +                        int icoord[4])
 +{
 +   uint ch;
 +
 +   /* s limited to [0,1) */
 +   /* i limited to [0,size-1] */
 +   for (ch = 0; ch < 4; ch++) {
 +      int i = util_ifloor(s[ch] * size);
 +      icoord[ch] = REMAINDER(i, size);
 +   }
 +}
 +
 +
 +static void
 +wrap_nearest_clamp(const float s[4], unsigned size,
                     int icoord[4])
  {
     uint ch;
 -   switch (wrapMode) {
 -   case PIPE_TEX_WRAP_REPEAT:
 -      /* s limited to [0,1) */
 -      /* i limited to [0,size-1] */
 -      for (ch = 0; ch < 4; ch++) {
 -         int i = util_ifloor(s[ch] * size);
 -         icoord[ch] = REMAINDER(i, size);
 -      }
 -      return;
 -   case PIPE_TEX_WRAP_CLAMP:
 +   /* s limited to [0,1] */
 +   /* i limited to [0,size-1] */
 +   for (ch = 0; ch < 4; ch++) {
 +      if (s[ch] <= 0.0F)
 +         icoord[ch] = 0;
 +      else if (s[ch] >= 1.0F)
 +         icoord[ch] = size - 1;
 +      else
 +         icoord[ch] = util_ifloor(s[ch] * size);
 +   }
 +}
 +
 +
 +static void
 +wrap_nearest_clamp_to_edge(const float s[4], unsigned size,
 +                           int icoord[4])
 +{
 +   uint ch;
 +   /* s limited to [min,max] */
 +   /* i limited to [0, size-1] */
 +   const float min = 1.0F / (2.0F * size);
 +   const float max = 1.0F - min;
 +   for (ch = 0; ch < 4; ch++) {
 +      if (s[ch] < min)
 +         icoord[ch] = 0;
 +      else if (s[ch] > max)
 +         icoord[ch] = size - 1;
 +      else
 +         icoord[ch] = util_ifloor(s[ch] * size);
 +   }
 +}
 +
 +
 +static void
 +wrap_nearest_clamp_to_border(const float s[4], unsigned size,
 +                             int icoord[4])
 +{
 +   uint ch;
 +   /* s limited to [min,max] */
 +   /* i limited to [-1, size] */
 +   const float min = -1.0F / (2.0F * size);
 +   const float max = 1.0F - min;
 +   for (ch = 0; ch < 4; ch++) {
 +      if (s[ch] <= min)
 +         icoord[ch] = -1;
 +      else if (s[ch] >= max)
 +         icoord[ch] = size;
 +      else
 +         icoord[ch] = util_ifloor(s[ch] * size);
 +   }
 +}
 +
 +static void
 +wrap_nearest_mirror_repeat(const float s[4], unsigned size,
 +                           int icoord[4])
 +{
 +   uint ch;
 +   const float min = 1.0F / (2.0F * size);
 +   const float max = 1.0F - min;
 +   for (ch = 0; ch < 4; ch++) {
 +      const int flr = util_ifloor(s[ch]);
 +      float u;
 +      if (flr & 1)
 +         u = 1.0F - (s[ch] - (float) flr);
 +      else
 +         u = s[ch] - (float) flr;
 +      if (u < min)
 +         icoord[ch] = 0;
 +      else if (u > max)
 +         icoord[ch] = size - 1;
 +      else
 +         icoord[ch] = util_ifloor(u * size);
 +   }
 +}
 +
 +static void
 +wrap_nearest_mirror_clamp(const float s[4], unsigned size,
 +                          int icoord[4])
 +{
 +   uint ch;
 +   for (ch = 0; ch < 4; ch++) {
        /* s limited to [0,1] */
        /* i limited to [0,size-1] */
 -      for (ch = 0; ch < 4; ch++) {
 -         if (s[ch] <= 0.0F)
 -            icoord[ch] = 0;
 -         else if (s[ch] >= 1.0F)
 -            icoord[ch] = size - 1;
 -         else
 -            icoord[ch] = util_ifloor(s[ch] * size);
 -      }
 -      return;
 -   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
 -      {
 -         /* s limited to [min,max] */
 -         /* i limited to [0, size-1] */
 -         const float min = 1.0F / (2.0F * size);
 -         const float max = 1.0F - min;
 -         for (ch = 0; ch < 4; ch++) {
 -            if (s[ch] < min)
 -               icoord[ch] = 0;
 -            else if (s[ch] > max)
 -               icoord[ch] = size - 1;
 -            else
 -               icoord[ch] = util_ifloor(s[ch] * size);
 -         }
 -      }
 -      return;
 -   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
 -      {
 -         /* s limited to [min,max] */
 -         /* i limited to [-1, size] */
 -         const float min = -1.0F / (2.0F * size);
 -         const float max = 1.0F - min;
 -         for (ch = 0; ch < 4; ch++) {
 -            if (s[ch] <= min)
 -               icoord[ch] = -1;
 -            else if (s[ch] >= max)
 -               icoord[ch] = size;
 -            else
 -               icoord[ch] = util_ifloor(s[ch] * size);
 -         }
 -      }
 -      return;
 -   case PIPE_TEX_WRAP_MIRROR_REPEAT:
 -      {
 -         const float min = 1.0F / (2.0F * size);
 -         const float max = 1.0F - min;
 -         for (ch = 0; ch < 4; ch++) {
 -            const int flr = util_ifloor(s[ch]);
 -            float u;
 -            if (flr & 1)
 -               u = 1.0F - (s[ch] - (float) flr);
 -            else
 -               u = s[ch] - (float) flr;
 -            if (u < min)
 -               icoord[ch] = 0;
 -            else if (u > max)
 -               icoord[ch] = size - 1;
 -            else
 -               icoord[ch] = util_ifloor(u * size);
 -         }
 -      }
 -      return;
 -   case PIPE_TEX_WRAP_MIRROR_CLAMP:
 -      for (ch = 0; ch < 4; ch++) {
 -         /* s limited to [0,1] */
 -         /* i limited to [0,size-1] */
 -         const float u = fabsf(s[ch]);
 -         if (u <= 0.0F)
 -            icoord[ch] = 0;
 -         else if (u >= 1.0F)
 -            icoord[ch] = size - 1;
 -         else
 -            icoord[ch] = util_ifloor(u * size);
 -      }
 -      return;
 -   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
 -      {
 -         /* s limited to [min,max] */
 -         /* i limited to [0, size-1] */
 -         const float min = 1.0F / (2.0F * size);
 -         const float max = 1.0F - min;
 -         for (ch = 0; ch < 4; ch++) {
 -            const float u = fabsf(s[ch]);
 -            if (u < min)
 -               icoord[ch] = 0;
 -            else if (u > max)
 -               icoord[ch] = size - 1;
 -            else
 -               icoord[ch] = util_ifloor(u * size);
 -         }
 -      }
 -      return;
 -   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
 -      {
 -         /* s limited to [min,max] */
 -         /* i limited to [0, size-1] */
 -         const float min = -1.0F / (2.0F * size);
 -         const float max = 1.0F - min;
 -         for (ch = 0; ch < 4; ch++) {
 -            const float u = fabsf(s[ch]);
 -            if (u < min)
 -               icoord[ch] = -1;
 -            else if (u > max)
 -               icoord[ch] = size;
 -            else
 -               icoord[ch] = util_ifloor(u * size);
 -         }
 -      }
 -      return;
 -   default:
 -      assert(0);
 +      const float u = fabsf(s[ch]);
 +      if (u <= 0.0F)
 +         icoord[ch] = 0;
 +      else if (u >= 1.0F)
 +         icoord[ch] = size - 1;
 +      else
 +         icoord[ch] = util_ifloor(u * size);
 +   }
 +}
 +
 +static void
 +wrap_nearest_mirror_clamp_to_edge(const float s[4], unsigned size,
 +                           int icoord[4])
 +{
 +   uint ch;
 +   /* s limited to [min,max] */
 +   /* i limited to [0, size-1] */
 +   const float min = 1.0F / (2.0F * size);
 +   const float max = 1.0F - min;
 +   for (ch = 0; ch < 4; ch++) {
 +      const float u = fabsf(s[ch]);
 +      if (u < min)
 +         icoord[ch] = 0;
 +      else if (u > max)
 +         icoord[ch] = size - 1;
 +      else
 +         icoord[ch] = util_ifloor(u * size);
 +   }
 +}
 +
 +
 +static void
 +wrap_nearest_mirror_clamp_to_border(const float s[4], unsigned size,
 +                                    int icoord[4])
 +{
 +   uint ch;
 +   /* s limited to [min,max] */
 +   /* i limited to [0, size-1] */
 +   const float min = -1.0F / (2.0F * size);
 +   const float max = 1.0F - min;
 +   for (ch = 0; ch < 4; ch++) {
 +      const float u = fabsf(s[ch]);
 +      if (u < min)
 +         icoord[ch] = -1;
 +      else if (u > max)
 +         icoord[ch] = size;
 +      else
 +         icoord[ch] = util_ifloor(u * size);
     }
  }
  
   * \param w  returns blend factor/weight between texture indexes
   * \param icoord  returns the computed integer texture coords
   */
 -static INLINE void
 -linear_texcoord_4(unsigned wrapMode, const float s[4], unsigned size,
 +static void
 +wrap_linear_repeat(const float s[4], unsigned size,
 +                   int icoord0[4], int icoord1[4], float w[4])
 +{
 +   uint ch;
 +
 +   for (ch = 0; ch < 4; ch++) {
 +      float u = s[ch] * size - 0.5F;
 +      icoord0[ch] = REMAINDER(util_ifloor(u), size);
 +      icoord1[ch] = REMAINDER(icoord0[ch] + 1, size);
 +      w[ch] = FRAC(u);
 +   }
 +}
 +
 +static void
 +wrap_linear_clamp(const float s[4], unsigned size,
                    int icoord0[4], int icoord1[4], float w[4])
  {
     uint ch;
 +   for (ch = 0; ch < 4; ch++) {
 +      float u = CLAMP(s[ch], 0.0F, 1.0F);
 +      u = u * size - 0.5f;
 +      icoord0[ch] = util_ifloor(u);
 +      icoord1[ch] = icoord0[ch] + 1;
 +      w[ch] = FRAC(u);
 +   }
 +}
  
 -   switch (wrapMode) {
 -   case PIPE_TEX_WRAP_REPEAT:
 -      for (ch = 0; ch < 4; ch++) {
 -         float u = s[ch] * size - 0.5F;
 -         icoord0[ch] = REMAINDER(util_ifloor(u), size);
 -         icoord1[ch] = REMAINDER(icoord0[ch] + 1, size);
 -         w[ch] = FRAC(u);
 -      }
 -      break;;
 -   case PIPE_TEX_WRAP_CLAMP:
 -      for (ch = 0; ch < 4; ch++) {
 -         float u = CLAMP(s[ch], 0.0F, 1.0F);
 -         u = u * size - 0.5f;
 -         icoord0[ch] = util_ifloor(u);
 -         icoord1[ch] = icoord0[ch] + 1;
 -         w[ch] = FRAC(u);
 -      }
 -      break;;
 -   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
 -      for (ch = 0; ch < 4; ch++) {
 -         float u = CLAMP(s[ch], 0.0F, 1.0F);
 -         u = u * size - 0.5f;
 -         icoord0[ch] = util_ifloor(u);
 -         icoord1[ch] = icoord0[ch] + 1;
 -         if (icoord0[ch] < 0)
 -            icoord0[ch] = 0;
 -         if (icoord1[ch] >= (int) size)
 -            icoord1[ch] = size - 1;
 -         w[ch] = FRAC(u);
 -      }
 -      break;;
 -   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
 -      {
 -         const float min = -1.0F / (2.0F * size);
 -         const float max = 1.0F - min;
 -         for (ch = 0; ch < 4; ch++) {
 -            float u = CLAMP(s[ch], min, max);
 -            u = u * size - 0.5f;
 -            icoord0[ch] = util_ifloor(u);
 -            icoord1[ch] = icoord0[ch] + 1;
 -            w[ch] = FRAC(u);
 -         }
 -      }
 -      break;;
 -   case PIPE_TEX_WRAP_MIRROR_REPEAT:
 -      for (ch = 0; ch < 4; ch++) {
 -         const int flr = util_ifloor(s[ch]);
 -         float u;
 -         if (flr & 1)
 -            u = 1.0F - (s[ch] - (float) flr);
 -         else
 -            u = s[ch] - (float) flr;
 -         u = u * size - 0.5F;
 -         icoord0[ch] = util_ifloor(u);
 -         icoord1[ch] = icoord0[ch] + 1;
 -         if (icoord0[ch] < 0)
 -            icoord0[ch] = 0;
 -         if (icoord1[ch] >= (int) size)
 -            icoord1[ch] = size - 1;
 -         w[ch] = FRAC(u);
 -      }
 -      break;;
 -   case PIPE_TEX_WRAP_MIRROR_CLAMP:
 -      for (ch = 0; ch < 4; ch++) {
 -         float u = fabsf(s[ch]);
 -         if (u >= 1.0F)
 -            u = (float) size;
 -         else
 -            u *= size;
 -         u -= 0.5F;
 -         icoord0[ch] = util_ifloor(u);
 -         icoord1[ch] = icoord0[ch] + 1;
 -         w[ch] = FRAC(u);
 -      }
 -      break;;
 -   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
 -      for (ch = 0; ch < 4; ch++) {
 -         float u = fabsf(s[ch]);
 -         if (u >= 1.0F)
 -            u = (float) size;
 -         else
 -            u *= size;
 -         u -= 0.5F;
 -         icoord0[ch] = util_ifloor(u);
 -         icoord1[ch] = icoord0[ch] + 1;
 -         if (icoord0[ch] < 0)
 -            icoord0[ch] = 0;
 -         if (icoord1[ch] >= (int) size)
 -            icoord1[ch] = size - 1;
 -         w[ch] = FRAC(u);
 -      }
 -      break;;
 -   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
 -      {
 -         const float min = -1.0F / (2.0F * size);
 -         const float max = 1.0F - min;
 -         for (ch = 0; ch < 4; ch++) {
 -            float u = fabsf(s[ch]);
 -            if (u <= min)
 -               u = min * size;
 -            else if (u >= max)
 -               u = max * size;
 -            else
 -               u *= size;
 -            u -= 0.5F;
 -            icoord0[ch] = util_ifloor(u);
 -            icoord1[ch] = icoord0[ch] + 1;
 -            w[ch] = FRAC(u);
 -         }
 -      }
 -      break;;
 -   default:
 -      assert(0);
 +static void
 +wrap_linear_clamp_to_edge(const float s[4], unsigned size,
 +                          int icoord0[4], int icoord1[4], float w[4])
 +{
 +   uint ch;
 +   for (ch = 0; ch < 4; ch++) {
 +      float u = CLAMP(s[ch], 0.0F, 1.0F);
 +      u = u * size - 0.5f;
 +      icoord0[ch] = util_ifloor(u);
 +      icoord1[ch] = icoord0[ch] + 1;
 +      if (icoord0[ch] < 0)
 +         icoord0[ch] = 0;
 +      if (icoord1[ch] >= (int) size)
 +         icoord1[ch] = size - 1;
 +      w[ch] = FRAC(u);
 +   }
 +}
 +
 +static void
 +wrap_linear_clamp_to_border(const float s[4], unsigned size,
 +                            int icoord0[4], int icoord1[4], float w[4])
 +{
 +   const float min = -1.0F / (2.0F * size);
 +   const float max = 1.0F - min;
 +   uint ch;
 +   for (ch = 0; ch < 4; ch++) {
 +      float u = CLAMP(s[ch], min, max);
 +      u = u * size - 0.5f;
 +      icoord0[ch] = util_ifloor(u);
 +      icoord1[ch] = icoord0[ch] + 1;
 +      w[ch] = FRAC(u);
 +   }
 +}
 +
 +
 +static void
 +wrap_linear_mirror_repeat(const float s[4], unsigned size,
 +                          int icoord0[4], int icoord1[4], float w[4])
 +{
 +   uint ch;
 +   for (ch = 0; ch < 4; ch++) {
 +      const int flr = util_ifloor(s[ch]);
 +      float u;
 +      if (flr & 1)
 +         u = 1.0F - (s[ch] - (float) flr);
 +      else
 +         u = s[ch] - (float) flr;
 +      u = u * size - 0.5F;
 +      icoord0[ch] = util_ifloor(u);
 +      icoord1[ch] = icoord0[ch] + 1;
 +      if (icoord0[ch] < 0)
 +         icoord0[ch] = 0;
 +      if (icoord1[ch] >= (int) size)
 +         icoord1[ch] = size - 1;
 +      w[ch] = FRAC(u);
 +   }
 +}
 +
 +static void
 +wrap_linear_mirror_clamp(const float s[4], unsigned size,
 +                         int icoord0[4], int icoord1[4], float w[4])
 +{
 +   uint ch;
 +   for (ch = 0; ch < 4; ch++) {
 +      float u = fabsf(s[ch]);
 +      if (u >= 1.0F)
 +         u = (float) size;
 +      else
 +         u *= size;
 +      u -= 0.5F;
 +      icoord0[ch] = util_ifloor(u);
 +      icoord1[ch] = icoord0[ch] + 1;
 +      w[ch] = FRAC(u);
 +   }
 +}
 +
 +static void
 +wrap_linear_mirror_clamp_to_edge(const float s[4], unsigned size,
 +                                 int icoord0[4], int icoord1[4], float w[4])
 +{
 +   uint ch;
 +   for (ch = 0; ch < 4; ch++) {
 +      float u = fabsf(s[ch]);
 +      if (u >= 1.0F)
 +         u = (float) size;
 +      else
 +         u *= size;
 +      u -= 0.5F;
 +      icoord0[ch] = util_ifloor(u);
 +      icoord1[ch] = icoord0[ch] + 1;
 +      if (icoord0[ch] < 0)
 +         icoord0[ch] = 0;
 +      if (icoord1[ch] >= (int) size)
 +         icoord1[ch] = size - 1;
 +      w[ch] = FRAC(u);
 +   }
 +}
 +
 +static void
 +wrap_linear_mirror_clamp_to_border(const float s[4], unsigned size,
 +                                   int icoord0[4], int icoord1[4], float w[4])
 +{
 +   const float min = -1.0F / (2.0F * size);
 +   const float max = 1.0F - min;
 +   uint ch;
 +   for (ch = 0; ch < 4; ch++) {
 +      float u = fabsf(s[ch]);
 +      if (u <= min)
 +         u = min * size;
 +      else if (u >= max)
 +         u = max * size;
 +      else
 +         u *= size;
 +      u -= 0.5F;
 +      icoord0[ch] = util_ifloor(u);
 +      icoord1[ch] = icoord0[ch] + 1;
 +      w[ch] = FRAC(u);
     }
  }
  
   * For RECT textures / unnormalized texcoords
   * Only a subset of wrap modes supported.
   */
 -static INLINE void
 -nearest_texcoord_unnorm_4(unsigned wrapMode, const float s[4], unsigned size,
 +static void
 +wrap_nearest_unorm_clamp(const float s[4], unsigned size,
                            int icoord[4])
  {
     uint ch;
 -   switch (wrapMode) {
 -   case PIPE_TEX_WRAP_CLAMP:
 -      for (ch = 0; ch < 4; ch++) {
 -         int i = util_ifloor(s[ch]);
 -         icoord[ch]= CLAMP(i, 0, (int) size-1);
 -      }
 -      return;
 -   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
 -      /* fall-through */
 -   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
 -      for (ch = 0; ch < 4; ch++) {
 -         icoord[ch]= util_ifloor( CLAMP(s[ch], 0.5F, (float) size - 0.5F) );
 -      }
 -      return;
 -   default:
 -      assert(0);
 +   for (ch = 0; ch < 4; ch++) {
 +      int i = util_ifloor(s[ch]);
 +      icoord[ch]= CLAMP(i, 0, (int) size-1);
 +   }
 +}
 +
 +/* Handles clamp_to_edge and clamp_to_border:
 + */
 +static void
 +wrap_nearest_unorm_clamp_to_border(const float s[4], unsigned size,
 +                               int icoord[4])
 +{
 +   uint ch;
 +   for (ch = 0; ch < 4; ch++) {
 +      icoord[ch]= util_ifloor( CLAMP(s[ch], 0.5F, (float) size - 0.5F) );
     }
  }
  
   * For RECT textures / unnormalized texcoords.
   * Only a subset of wrap modes supported.
   */
 -static INLINE void
 -linear_texcoord_unnorm_4(unsigned wrapMode, const float s[4], unsigned size,
 +static void
 +wrap_linear_unorm_clamp(const float s[4], unsigned size,
                           int icoord0[4], int icoord1[4], float w[4])
  {
     uint ch;
 -   switch (wrapMode) {
 -   case PIPE_TEX_WRAP_CLAMP:
 -      for (ch = 0; ch < 4; ch++) {
 -         /* Not exactly what the spec says, but it matches NVIDIA output */
 -         float u = CLAMP(s[ch] - 0.5F, 0.0f, (float) size - 1.0f);
 -         icoord0[ch] = util_ifloor(u);
 -         icoord1[ch] = icoord0[ch] + 1;
 -         w[ch] = FRAC(u);
 -      }
 -      return;
 -   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
 -      /* fall-through */
 -   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
 -      for (ch = 0; ch < 4; ch++) {
 -         float u = CLAMP(s[ch], 0.5F, (float) size - 0.5F);
 -         u -= 0.5F;
 -         icoord0[ch] = util_ifloor(u);
 -         icoord1[ch] = icoord0[ch] + 1;
 -         if (icoord1[ch] > (int) size - 1)
 -            icoord1[ch] = size - 1;
 -         w[ch] = FRAC(u);
 -      }
 -      break;
 -   default:
 -      assert(0);
 +   for (ch = 0; ch < 4; ch++) {
 +      /* Not exactly what the spec says, but it matches NVIDIA output */
 +      float u = CLAMP(s[ch] - 0.5F, 0.0f, (float) size - 1.0f);
 +      icoord0[ch] = util_ifloor(u);
 +      icoord1[ch] = icoord0[ch] + 1;
 +      w[ch] = FRAC(u);
     }
  }
  
 -
 -static unsigned
 -choose_cube_face(float rx, float ry, float rz, float *newS, float *newT)
 +static void
 +wrap_linear_unorm_clamp_to_border( const float s[4], unsigned size,
 +                                   int icoord0[4], int icoord1[4], float w[4])
  {
 -   /*
 -      major axis
 -      direction     target                             sc     tc    ma
 -      ----------    -------------------------------    ---    ---   ---
 -       +rx          TEXTURE_CUBE_MAP_POSITIVE_X_EXT    -rz    -ry   rx
 -       -rx          TEXTURE_CUBE_MAP_NEGATIVE_X_EXT    +rz    -ry   rx
 -       +ry          TEXTURE_CUBE_MAP_POSITIVE_Y_EXT    +rx    +rz   ry
 -       -ry          TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT    +rx    -rz   ry
 -       +rz          TEXTURE_CUBE_MAP_POSITIVE_Z_EXT    +rx    -ry   rz
 -       -rz          TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT    -rx    -ry   rz
 -   */
 -   const float arx = fabsf(rx), ary = fabsf(ry), arz = fabsf(rz);
 -   unsigned face;
 -   float sc, tc, ma;
 -
 -   if (arx > ary && arx > arz) {
 -      if (rx >= 0.0F) {
 -         face = PIPE_TEX_FACE_POS_X;
 -         sc = -rz;
 -         tc = -ry;
 -         ma = arx;
 -      }
 -      else {
 -         face = PIPE_TEX_FACE_NEG_X;
 -         sc = rz;
 -         tc = -ry;
 -         ma = arx;
 -      }
 -   }
 -   else if (ary > arx && ary > arz) {
 -      if (ry >= 0.0F) {
 -         face = PIPE_TEX_FACE_POS_Y;
 -         sc = rx;
 -         tc = rz;
 -         ma = ary;
 -      }
 -      else {
 -         face = PIPE_TEX_FACE_NEG_Y;
 -         sc = rx;
 -         tc = -rz;
 -         ma = ary;
 -      }
 -   }
 -   else {
 -      if (rz > 0.0F) {
 -         face = PIPE_TEX_FACE_POS_Z;
 -         sc = rx;
 -         tc = -ry;
 -         ma = arz;
 -      }
 -      else {
 -         face = PIPE_TEX_FACE_NEG_Z;
 -         sc = -rx;
 -         tc = -ry;
 -         ma = arz;
 -      }
 +   uint ch;
 +   for (ch = 0; ch < 4; ch++) {
 +      float u = CLAMP(s[ch], 0.5F, (float) size - 0.5F);
 +      u -= 0.5F;
 +      icoord0[ch] = util_ifloor(u);
 +      icoord1[ch] = icoord0[ch] + 1;
 +      if (icoord1[ch] > (int) size - 1)
 +         icoord1[ch] = size - 1;
 +      w[ch] = FRAC(u);
     }
 +}
 +
  
 -   *newS = ( sc / ma + 1.0F ) * 0.5F;
 -   *newT = ( tc / ma + 1.0F ) * 0.5F;
  
 -   return face;
 -}
  
  
  /**
   * Examine the quad's texture coordinates to compute the partial
   * derivatives w.r.t X and Y, then compute lambda (level of detail).
 - *
 - * This is only done for fragment shaders, not vertex shaders.
   */
  static float
 -compute_lambda(const struct pipe_texture *tex,
 -               const struct pipe_sampler_state *sampler,
 -               const float s[QUAD_SIZE],
 -               const float t[QUAD_SIZE],
 -               const float p[QUAD_SIZE],
 -               float lodbias)
 +compute_lambda_1d(const struct sp_sampler_varient *samp,
 +                  const float s[QUAD_SIZE],
 +                  const float t[QUAD_SIZE],
 +                  const float p[QUAD_SIZE],
 +                  float lodbias)
  {
 -   float rho, lambda;
 +   const struct pipe_texture *texture = samp->texture;
 +   const struct pipe_sampler_state *sampler = samp->sampler;
 +   float dsdx = fabsf(s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]);
 +   float dsdy = fabsf(s[QUAD_TOP_LEFT]     - s[QUAD_BOTTOM_LEFT]);
 +   float rho = MAX2(dsdx, dsdy) * texture->width[0];
 +   float lambda;
  
 -   assert(sampler->normalized_coords);
 +   lambda = util_fast_log2(rho);
 +   lambda += lodbias + sampler->lod_bias;
 +   lambda = CLAMP(lambda, sampler->min_lod, sampler->max_lod);
  
 -   assert(s);
 -   {
 -      float dsdx = s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT];
 -      float dsdy = s[QUAD_TOP_LEFT]     - s[QUAD_BOTTOM_LEFT];
 -      dsdx = fabsf(dsdx);
 -      dsdy = fabsf(dsdy);
 -      rho = MAX2(dsdx, dsdy) * tex->width[0];
 -   }
 -   if (t) {
 -      float dtdx = t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT];
 -      float dtdy = t[QUAD_TOP_LEFT]     - t[QUAD_BOTTOM_LEFT];
 -      float max;
 -      dtdx = fabsf(dtdx);
 -      dtdy = fabsf(dtdy);
 -      max = MAX2(dtdx, dtdy) * tex->height[0];
 -      rho = MAX2(rho, max);
 -   }
 -   if (p) {
 -      float dpdx = p[QUAD_BOTTOM_RIGHT] - p[QUAD_BOTTOM_LEFT];
 -      float dpdy = p[QUAD_TOP_LEFT]     - p[QUAD_BOTTOM_LEFT];
 -      float max;
 -      dpdx = fabsf(dpdx);
 -      dpdy = fabsf(dpdy);
 -      max = MAX2(dpdx, dpdy) * tex->depth[0];
 -      rho = MAX2(rho, max);
 -   }
 +   return lambda;
 +}
 +
 +static float
 +compute_lambda_2d(const struct sp_sampler_varient *samp,
 +                  const float s[QUAD_SIZE],
 +                  const float t[QUAD_SIZE],
 +                  const float p[QUAD_SIZE],
 +                  float lodbias)
 +{
 +   const struct pipe_texture *texture = samp->texture;
 +   const struct pipe_sampler_state *sampler = samp->sampler;
 +   float dsdx = fabsf(s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]);
 +   float dsdy = fabsf(s[QUAD_TOP_LEFT]     - s[QUAD_BOTTOM_LEFT]);
 +   float dtdx = fabsf(t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT]);
 +   float dtdy = fabsf(t[QUAD_TOP_LEFT]     - t[QUAD_BOTTOM_LEFT]);
 +   float maxx = MAX2(dsdx, dsdy) * texture->width[0];
 +   float maxy = MAX2(dtdx, dtdy) * texture->height[0];
 +   float rho  = MAX2(maxx, maxy);
 +   float lambda;
  
     lambda = util_fast_log2(rho);
     lambda += lodbias + sampler->lod_bias;
  }
  
  
 -/**
 - * Do several things here:
 - * 1. Compute lambda from the texcoords, if needed
 - * 2. Determine if we're minifying or magnifying
 - * 3. If minifying, choose mipmap levels
 - * 4. Return image filter to use within mipmap images
 - * \param level0  Returns first mipmap level to sample from
 - * \param level1  Returns second mipmap level to sample from
 - * \param levelBlend  Returns blend factor between levels, in [0,1]
 - * \param imgFilter  Returns either the min or mag filter, depending on lambda
 - */
 -static void
 -choose_mipmap_levels(const struct pipe_texture *texture,
 -                     const struct pipe_sampler_state *sampler,
 -                     const float s[QUAD_SIZE],
 -                     const float t[QUAD_SIZE],
 -                     const float p[QUAD_SIZE],
 -                     boolean computeLambda,
 -                     float lodbias,
 -                     unsigned *level0, unsigned *level1, float *levelBlend,
 -                     unsigned *imgFilter)
 +static float
 +compute_lambda_3d(const struct sp_sampler_varient *samp,
 +                  const float s[QUAD_SIZE],
 +                  const float t[QUAD_SIZE],
 +                  const float p[QUAD_SIZE],
 +                  float lodbias)
  {
 -   if (sampler->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) {
 -      /* no mipmap selection needed */
 -      *level0 = *level1 = CLAMP((int) sampler->min_lod,
 -                                0, (int) texture->last_level);
 -
 -      if (sampler->min_img_filter != sampler->mag_img_filter) {
 -         /* non-mipmapped texture, but still need to determine if doing
 -          * minification or magnification.
 -          */
 -         float lambda = compute_lambda(texture, sampler, s, t, p, lodbias);
 -         if (lambda <= 0.0) {
 -            *imgFilter = sampler->mag_img_filter;
 -         }
 -         else {
 -            *imgFilter = sampler->min_img_filter;
 -         }
 -      }
 -      else {
 -         *imgFilter = sampler->mag_img_filter;
 -      }
 -   }
 -   else {
 -      float lambda;
 +   const struct pipe_texture *texture = samp->texture;
 +   const struct pipe_sampler_state *sampler = samp->sampler;
 +   float dsdx = fabsf(s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]);
 +   float dsdy = fabsf(s[QUAD_TOP_LEFT]     - s[QUAD_BOTTOM_LEFT]);
 +   float dtdx = fabsf(t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT]);
 +   float dtdy = fabsf(t[QUAD_TOP_LEFT]     - t[QUAD_BOTTOM_LEFT]);
 +   float dpdx = fabsf(p[QUAD_BOTTOM_RIGHT] - p[QUAD_BOTTOM_LEFT]);
 +   float dpdy = fabsf(p[QUAD_TOP_LEFT]     - p[QUAD_BOTTOM_LEFT]);
 +   float maxx = MAX2(dsdx, dsdy) * texture->width[0];
 +   float maxy = MAX2(dtdx, dtdy) * texture->height[0];
 +   float maxz = MAX2(dpdx, dpdy) * texture->depth[0];
 +   float rho, lambda;
  
 -      if (computeLambda)
 -         /* fragment shader */
 -         lambda = compute_lambda(texture, sampler, s, t, p, lodbias);
 -      else
 -         /* vertex shader */
 -         lambda = lodbias; /* not really a bias, but absolute LOD */
 +   rho = MAX2(maxx, maxy);
 +   rho = MAX2(rho, maxz);
  
 -      if (lambda <= 0.0) { /* XXX threshold depends on the filter */
 -         /* magnifying */
 -         *imgFilter = sampler->mag_img_filter;
 -         *level0 = *level1 = 0;
 -      }
 -      else {
 -         /* minifying */
 -         *imgFilter = sampler->min_img_filter;
 -
 -         /* choose mipmap level(s) and compute the blend factor between them */
 -         if (sampler->min_mip_filter == PIPE_TEX_MIPFILTER_NEAREST) {
 -            /* Nearest mipmap level */
 -            const int lvl = (int) (lambda + 0.5);
 -            *level0 =
 -            *level1 = CLAMP(lvl, 0, (int) texture->last_level);
 -         }
 -         else {
 -            /* Linear interpolation between mipmap levels */
 -            const int lvl = (int) lambda;
 -            *level0 = CLAMP(lvl,     0, (int) texture->last_level);
 -            *level1 = CLAMP(lvl + 1, 0, (int) texture->last_level);
 -            *levelBlend = FRAC(lambda);  /* blending weight between levels */
 -         }
 -      }
 -   }
 +   lambda = util_fast_log2(rho);
 +   lambda += lodbias + sampler->lod_bias;
 +   lambda = CLAMP(lambda, sampler->min_lod, sampler->max_lod);
 +
 +   return lambda;
  }
  
  
 +
 +static float
 +compute_lambda_vert(const struct sp_sampler_varient *samp,
 +                    const float s[QUAD_SIZE],
 +                    const float t[QUAD_SIZE],
 +                    const float p[QUAD_SIZE],
 +                    float lodbias)
 +{
 +   return lodbias;
 +}
 +
 +
 +
  /**
   * Get a texel from a texture, using the texture tile cache.
   *
   * \param rgba  the quad to put the texel/color into
   * \param j  which element of the rgba quad to write to
   *
-  * XXX maybe move this into sp_tile_cache.c and merge with the
+  * XXX maybe move this into sp_tex_tile_cache.c and merge with the
   * sp_get_cached_tile_tex() function.  Also, get 4 texels instead of 1...
   */
 -static void
 +static INLINE void
  get_texel_quad_2d(const struct tgsi_sampler *tgsi_sampler,
                    unsigned face, unsigned level, int x, int y, 
                    const float *out[4])
  {
 -   const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
 +   const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
  
-    const struct softpipe_cached_tile *tile
+    const struct softpipe_tex_cached_tile *tile
        = sp_get_cached_tile_tex(samp->cache,
-                                tile_address(x, y, 0, face, level));
+                                tex_tile_address(x, y, 0, face, level));
  
     y %= TILE_SIZE;
     x %= TILE_SIZE;
@@@ -627,11 -686,11 +627,11 @@@ static INLINE const float 
  get_texel_2d_ptr(const struct tgsi_sampler *tgsi_sampler,
                   unsigned face, unsigned level, int x, int y)
  {
 -   const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
 +   const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
  
-    const struct softpipe_cached_tile *tile
+    const struct softpipe_tex_cached_tile *tile
        = sp_get_cached_tile_tex(samp->cache,
-                                tile_address(x, y, 0, face, level));
+                                tex_tile_address(x, y, 0, face, level));
  
     y %= TILE_SIZE;
     x %= TILE_SIZE;
  }
  
  
 -static void
 +static INLINE void
  get_texel_quad_2d_mt(const struct tgsi_sampler *tgsi_sampler,
                       unsigned face, unsigned level, 
                       int x0, int y0, 
     }
  }
  
 -static void
 +static INLINE void
  get_texel(const struct tgsi_sampler *tgsi_sampler,
                   unsigned face, unsigned level, int x, int y, int z,
                   float rgba[NUM_CHANNELS][QUAD_SIZE], unsigned j)
  {
 -   const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
 +   const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
     const struct pipe_texture *texture = samp->texture;
     const struct pipe_sampler_state *sampler = samp->sampler;
  
     else {
        const unsigned tx = x % TILE_SIZE;
        const unsigned ty = y % TILE_SIZE;
-       const struct softpipe_cached_tile *tile;
+       const struct softpipe_tex_cached_tile *tile;
  
        tile = sp_get_cached_tile_tex(samp->cache, 
-                                     tile_address(x, y, z, face, level));
+                                     tex_tile_address(x, y, z, face, level));
  
        rgba[0][j] = tile->data.color[ty][tx][0];
        rgba[1][j] = tile->data.color[ty][tx][1];
  }
  
  
 -/**
 - * Compare texcoord 'p' (aka R) against texture value 'rgba[0]'
 - * When we sampled the depth texture, the depth value was put into all
 - * RGBA channels.  We look at the red channel here.
 - * \param rgba  quad of (depth) texel values
 - * \param p  texture 'P' components for four pixels in quad
 - * \param j  which pixel in the quad to test [0..3]
 - */
 -static INLINE void
 -shadow_compare(const struct pipe_sampler_state *sampler,
 -               float rgba[NUM_CHANNELS][QUAD_SIZE],
 -               const float p[QUAD_SIZE],
 -               uint j)
 -{
 -   int k;
 -   switch (sampler->compare_func) {
 -   case PIPE_FUNC_LESS:
 -      k = p[j] < rgba[0][j];
 -      break;
 -   case PIPE_FUNC_LEQUAL:
 -      k = p[j] <= rgba[0][j];
 -      break;
 -   case PIPE_FUNC_GREATER:
 -      k = p[j] > rgba[0][j];
 -      break;
 -   case PIPE_FUNC_GEQUAL:
 -      k = p[j] >= rgba[0][j];
 -      break;
 -   case PIPE_FUNC_EQUAL:
 -      k = p[j] == rgba[0][j];
 -      break;
 -   case PIPE_FUNC_NOTEQUAL:
 -      k = p[j] != rgba[0][j];
 -      break;
 -   case PIPE_FUNC_ALWAYS:
 -      k = 1;
 -      break;
 -   case PIPE_FUNC_NEVER:
 -      k = 0;
 -      break;
 -   default:
 -      k = 0;
 -      assert(0);
 -      break;
 -   }
  
 -   /* XXX returning result for default GL_DEPTH_TEXTURE_MODE = GL_LUMINANCE */
 -   rgba[0][j] = rgba[1][j] = rgba[2][j] = (float) k;
 -   rgba[3][j] = 1.0F;
 -}
  
  
 -/**
 - * As above, but do four z/texture comparisons.
 - */
  static INLINE void
 -shadow_compare4(const struct pipe_sampler_state *sampler,
 -                float rgba[NUM_CHANNELS][QUAD_SIZE],
 -                const float p[QUAD_SIZE])
 -{
 -   int j, k0, k1, k2, k3;
 -   float val;
 -
 -   /* compare four texcoords vs. four texture samples */
 -   switch (sampler->compare_func) {
 -   case PIPE_FUNC_LESS:
 -      k0 = p[0] < rgba[0][0];
 -      k1 = p[1] < rgba[0][1];
 -      k2 = p[2] < rgba[0][2];
 -      k3 = p[3] < rgba[0][3];
 -      break;
 -   case PIPE_FUNC_LEQUAL:
 -      k0 = p[0] <= rgba[0][0];
 -      k1 = p[1] <= rgba[0][1];
 -      k2 = p[2] <= rgba[0][2];
 -      k3 = p[3] <= rgba[0][3];
 -      break;
 -   case PIPE_FUNC_GREATER:
 -      k0 = p[0] > rgba[0][0];
 -      k1 = p[1] > rgba[0][1];
 -      k2 = p[2] > rgba[0][2];
 -      k3 = p[3] > rgba[0][3];
 -      break;
 -   case PIPE_FUNC_GEQUAL:
 -      k0 = p[0] >= rgba[0][0];
 -      k1 = p[1] >= rgba[0][1];
 -      k2 = p[2] >= rgba[0][2];
 -      k3 = p[3] >= rgba[0][3];
 -      break;
 -   case PIPE_FUNC_EQUAL:
 -      k0 = p[0] == rgba[0][0];
 -      k1 = p[1] == rgba[0][1];
 -      k2 = p[2] == rgba[0][2];
 -      k3 = p[3] == rgba[0][3];
 -      break;
 -   case PIPE_FUNC_NOTEQUAL:
 -      k0 = p[0] != rgba[0][0];
 -      k1 = p[1] != rgba[0][1];
 -      k2 = p[2] != rgba[0][2];
 -      k3 = p[3] != rgba[0][3];
 -      break;
 -   case PIPE_FUNC_ALWAYS:
 -      k0 = k1 = k2 = k3 = 1;
 -      break;
 -   case PIPE_FUNC_NEVER:
 -      k0 = k1 = k2 = k3 = 0;
 -      break;
 -   default:
 -      k0 = k1 = k2 = k3 = 0;
 -      assert(0);
 -      break;
 -   }
 -
 -   /* convert four pass/fail values to an intensity in [0,1] */
 -   val = 0.25F * (k0 + k1 + k2 + k3);
 -
 -   /* XXX returning result for default GL_DEPTH_TEXTURE_MODE = GL_LUMINANCE */
 -   for (j = 0; j < 4; j++) {
 -      rgba[0][j] = rgba[1][j] = rgba[2][j] = val;
 -      rgba[3][j] = 1.0F;
 -   }
 -}
 -
 -
 -
 -static void
 -sp_get_samples_2d_linear_repeat_POT(struct tgsi_sampler *tgsi_sampler,
 -                                    const float s[QUAD_SIZE],
 -                                    const float t[QUAD_SIZE],
 -                                    const float p[QUAD_SIZE],
 -                                    float lodbias,
 -                                    float rgba[NUM_CHANNELS][QUAD_SIZE])
 +img_filter_2d_linear_repeat_POT(struct tgsi_sampler *tgsi_sampler,
 +                                  const float s[QUAD_SIZE],
 +                                  const float t[QUAD_SIZE],
 +                                  const float p[QUAD_SIZE],
 +                                  float lodbias,
 +                                  float rgba[NUM_CHANNELS][QUAD_SIZE])
  {
 -   const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
 +   const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
     unsigned  j;
     unsigned level = samp->level;
     unsigned xpot = 1 << (samp->xpot - level);
     unsigned ypot = 1 << (samp->ypot - level);
 -
 +   unsigned xmax = (xpot - 1) & (TILE_SIZE - 1); /* MIN2(TILE_SIZE, xpot) - 1; */
 +   unsigned ymax = (ypot - 1) & (TILE_SIZE - 1); /* MIN2(TILE_SIZE, ypot) - 1; */
 +      
     for (j = 0; j < QUAD_SIZE; j++) {
        int c;
  
  
        /* Can we fetch all four at once:
         */
 -      if (x0 % TILE_SIZE != TILE_SIZE-1 &&
 -          y0 % TILE_SIZE != TILE_SIZE-1)
 +      if (x0 < xmax && y0 < ymax)
        {
           get_texel_quad_2d(tgsi_sampler, 0, level, x0, y0, tx);
        }
        else 
        {
 -         unsigned x1 = (uflr + 1) & (xpot - 1);
 -         unsigned y1 = (vflr + 1) & (ypot - 1);
 +         unsigned x1 = (x0 + 1) & (xpot - 1);
 +         unsigned y1 = (y0 + 1) & (ypot - 1);
           get_texel_quad_2d_mt(tgsi_sampler, 0, level, 
                                x0, y0, x1, y1, tx);
        }
  }
  
  
 -static void
 -sp_get_samples_2d_nearest_repeat_POT(struct tgsi_sampler *tgsi_sampler,
 -                                     const float s[QUAD_SIZE],
 -                                     const float t[QUAD_SIZE],
 -                                     const float p[QUAD_SIZE],
 -                                     float lodbias,
 -                                     float rgba[NUM_CHANNELS][QUAD_SIZE])
 +static INLINE void
 +img_filter_2d_nearest_repeat_POT(struct tgsi_sampler *tgsi_sampler,
 +                                 const float s[QUAD_SIZE],
 +                                 const float t[QUAD_SIZE],
 +                                 const float p[QUAD_SIZE],
 +                                 float lodbias,
 +                                 float rgba[NUM_CHANNELS][QUAD_SIZE])
  {
 -   const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
 +   const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
     unsigned  j;
     unsigned level = samp->level;
     unsigned xpot = 1 << (samp->xpot - level);
  }
  
  
 -static void
 -sp_get_samples_2d_nearest_clamp_POT(struct tgsi_sampler *tgsi_sampler,
 -                                     const float s[QUAD_SIZE],
 -                                     const float t[QUAD_SIZE],
 -                                     const float p[QUAD_SIZE],
 -                                     float lodbias,
 -                                     float rgba[NUM_CHANNELS][QUAD_SIZE])
 +static INLINE void
 +img_filter_2d_nearest_clamp_POT(struct tgsi_sampler *tgsi_sampler,
 +                                const float s[QUAD_SIZE],
 +                                const float t[QUAD_SIZE],
 +                                const float p[QUAD_SIZE],
 +                                float lodbias,
 +                                float rgba[NUM_CHANNELS][QUAD_SIZE])
  {
 -   const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
 +   const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
     unsigned  j;
     unsigned level = samp->level;
 -   unsigned xpot = (1<<samp->xpot);
 -   unsigned ypot = (1<<samp->ypot);
 +   unsigned xpot = 1 << (samp->xpot - level);
 +   unsigned ypot = 1 << (samp->ypot - level);
  
     for (j = 0; j < QUAD_SIZE; j++) {
        int c;
     }
  }
  
 -
  static void
 -sp_get_samples_2d_linear_mip_linear_repeat_POT(struct tgsi_sampler *tgsi_sampler,
 -                                               const float s[QUAD_SIZE],
 -                                               const float t[QUAD_SIZE],
 -                                               const float p[QUAD_SIZE],
 -                                               float lodbias,
 -                                               float rgba[NUM_CHANNELS][QUAD_SIZE])
 +img_filter_1d_nearest(struct tgsi_sampler *tgsi_sampler,
 +                        const float s[QUAD_SIZE],
 +                        const float t[QUAD_SIZE],
 +                        const float p[QUAD_SIZE],
 +                        float lodbias,
 +                        float rgba[NUM_CHANNELS][QUAD_SIZE])
  {
 -   struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
 +   const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
     const struct pipe_texture *texture = samp->texture;
 -   const struct pipe_sampler_state *sampler = samp->sampler;
 -   int level0, level1;
 -   float lambda;
 -
 -   lambda = compute_lambda(texture, sampler, s, t, p, lodbias);
 -   level0 = (int)lambda;
 -   level1 = level0 + 1;
 -
 -   if (lambda < 0.0) { 
 -      samp->level = 0;
 -      sp_get_samples_2d_linear_repeat_POT( tgsi_sampler,
 -                                           s, t, p, lodbias, rgba );
 -   }
 -   else if (level0 >= texture->last_level) {
 -      samp->level = texture->last_level;
 -      sp_get_samples_2d_linear_repeat_POT( tgsi_sampler,
 -                                           s, t, p, lodbias, rgba );
 -   }
 -   else {
 -      float rgba0[4][4];
 -      float rgba1[4][4];
 -      int c,j;
 +   unsigned level0, j;
 +   int width;
 +   int x[4];
  
 -      float levelBlend = lambda - level0;  /* blending weight between levels */
 +   level0 = samp->level;
 +   width = texture->width[level0];
  
 -      samp->level = level0;
 -      sp_get_samples_2d_linear_repeat_POT( tgsi_sampler,
 -                                           s, t, p, lodbias, rgba0 );
 +   assert(width > 0);
  
 -      samp->level++;
 -      sp_get_samples_2d_linear_repeat_POT( tgsi_sampler,
 -                                           s, t, p, lodbias, rgba1 );
 +   samp->nearest_texcoord_s(s, width, x);
  
 -      for (c = 0; c < 4; c++) 
 -         for (j = 0; j < 4; j++)
 -            rgba[c][j] = lerp(levelBlend, rgba0[c][j], rgba1[c][j]);
 -  }
 +   for (j = 0; j < QUAD_SIZE; j++) {
 +      get_texel(tgsi_sampler, 0, level0, x[j], 0, 0, rgba, j);
 +   }
  }
  
 -/**
 - * Common code for sampling 1D/2D/cube textures.
 - * Could probably extend for 3D...
 - */
 +
  static void
 -sp_get_samples_2d_common(const struct tgsi_sampler *tgsi_sampler,
 -                         const float s[QUAD_SIZE],
 -                         const float t[QUAD_SIZE],
 -                         const float p[QUAD_SIZE],
 -                         boolean computeLambda,
 -                         float lodbias,
 -                         float rgba[NUM_CHANNELS][QUAD_SIZE],
 -                         const unsigned faces[4])
 +img_filter_2d_nearest(struct tgsi_sampler *tgsi_sampler,
 +                      const float s[QUAD_SIZE],
 +                      const float t[QUAD_SIZE],
 +                      const float p[QUAD_SIZE],
 +                      float lodbias,
 +                      float rgba[NUM_CHANNELS][QUAD_SIZE])
  {
 -   const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
 +   const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
     const struct pipe_texture *texture = samp->texture;
 -   const struct pipe_sampler_state *sampler = samp->sampler;
 -   unsigned level0, level1, j, imgFilter;
 +   const unsigned *faces = samp->faces; /* zero when not cube-mapping */
 +   unsigned level0, j;
     int width, height;
 -   float levelBlend;
 -
 -   choose_mipmap_levels(texture, sampler, s, t, p, computeLambda, lodbias,
 -                        &level0, &level1, &levelBlend, &imgFilter);
 -
 -   assert(sampler->normalized_coords);
 +   int x[4], y[4];
  
 +   level0 = samp->level;
     width = texture->width[level0];
     height = texture->height[level0];
  
     assert(width > 0);
  
 -   switch (imgFilter) {
 -   case PIPE_TEX_FILTER_NEAREST:
 -      {
 -         int x[4], y[4];
 -         nearest_texcoord_4(sampler->wrap_s, s, width, x);
 -         nearest_texcoord_4(sampler->wrap_t, t, height, y);
 -
 -         for (j = 0; j < QUAD_SIZE; j++) {
 -            get_texel(tgsi_sampler, faces[j], level0, x[j], y[j], 0, rgba, j);
 -            if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
 -               shadow_compare(sampler, rgba, p, j);
 -            }
 -
 -            if (level0 != level1) {
 -               /* get texels from second mipmap level and blend */
 -               float rgba2[4][4];
 -               unsigned c;
 -               x[j] /= 2;
 -               y[j] /= 2;
 -               get_texel(tgsi_sampler, faces[j], level1, x[j], y[j], 0,
 -                         rgba2, j);
 -               if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
 -                  shadow_compare(sampler, rgba2, p, j);
 -               }
 -
 -               for (c = 0; c < NUM_CHANNELS; c++) {
 -                  rgba[c][j] = lerp(levelBlend, rgba[c][j], rgba2[c][j]);
 -               }
 -            }
 -         }
 -      }
 -      break;
 -   case PIPE_TEX_FILTER_LINEAR:
 -   case PIPE_TEX_FILTER_ANISO:
 -      {
 -         int x0[4], y0[4], x1[4], y1[4];
 -         float xw[4], yw[4]; /* weights */
 -
 -         linear_texcoord_4(sampler->wrap_s, s, width, x0, x1, xw);
 -         linear_texcoord_4(sampler->wrap_t, t, height, y0, y1, yw);
 -
 -         for (j = 0; j < QUAD_SIZE; j++) {
 -            float tx[4][4]; /* texels */
 -            int c;
 -            get_texel(tgsi_sampler, faces[j], level0, x0[j], y0[j], 0, tx, 0);
 -            get_texel(tgsi_sampler, faces[j], level0, x1[j], y0[j], 0, tx, 1);
 -            get_texel(tgsi_sampler, faces[j], level0, x0[j], y1[j], 0, tx, 2);
 -            get_texel(tgsi_sampler, faces[j], level0, x1[j], y1[j], 0, tx, 3);
 -            if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
 -               shadow_compare4(sampler, tx, p);
 -            }
 -
 -            /* interpolate R, G, B, A */
 -            for (c = 0; c < 4; c++) {
 -               rgba[c][j] = lerp_2d(xw[j], yw[j],
 -                                    tx[c][0], tx[c][1],
 -                                    tx[c][2], tx[c][3]);
 -            }
 +   samp->nearest_texcoord_s(s, width, x);
 +   samp->nearest_texcoord_t(t, height, y);
  
 -            if (level0 != level1) {
 -               /* get texels from second mipmap level and blend */
 -               float rgba2[4][4];
 -               x0[j] /= 2;
 -               y0[j] /= 2;
 -               x1[j] /= 2;
 -               y1[j] /= 2;
 -               get_texel(tgsi_sampler, faces[j], level1, x0[j], y0[j], 0, tx, 0);
 -               get_texel(tgsi_sampler, faces[j], level1, x1[j], y0[j], 0, tx, 1);
 -               get_texel(tgsi_sampler, faces[j], level1, x0[j], y1[j], 0, tx, 2);
 -               get_texel(tgsi_sampler, faces[j], level1, x1[j], y1[j], 0, tx, 3);
 -               if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
 -                  shadow_compare4(sampler, tx, p);
 -               }
 -
 -               /* interpolate R, G, B, A */
 -               for (c = 0; c < 4; c++) {
 -                  rgba2[c][j] = lerp_2d(xw[j], yw[j],
 -                                        tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
 -               }
 -
 -               for (c = 0; c < NUM_CHANNELS; c++) {
 -                  rgba[c][j] = lerp(levelBlend, rgba[c][j], rgba2[c][j]);
 -               }
 -            }
 -         }
 -      }
 -      break;
 -   default:
 -      assert(0);
 +   for (j = 0; j < QUAD_SIZE; j++) {
 +      get_texel(tgsi_sampler, faces[j], level0, x[j], y[j], 0, rgba, j);
     }
  }
  
  
 -static INLINE void
 -sp_get_samples_1d(const struct tgsi_sampler *sampler,
 -                  const float s[QUAD_SIZE],
 -                  const float t[QUAD_SIZE],
 -                  const float p[QUAD_SIZE],
 -                  boolean computeLambda,
 -                  float lodbias,
 -                  float rgba[NUM_CHANNELS][QUAD_SIZE])
 -{
 -   static const unsigned faces[4] = {0, 0, 0, 0};
 -   static const float tzero[4] = {0, 0, 0, 0};
 -   sp_get_samples_2d_common(sampler, s, tzero, NULL,
 -                            computeLambda, lodbias, rgba, faces);
 -}
 -
 -
 -static INLINE void
 -sp_get_samples_2d(const struct tgsi_sampler *sampler,
 -                  const float s[QUAD_SIZE],
 -                  const float t[QUAD_SIZE],
 -                  const float p[QUAD_SIZE],
 -                  boolean computeLambda,
 -                  float lodbias,
 -                  float rgba[NUM_CHANNELS][QUAD_SIZE])
 -{
 -   static const unsigned faces[4] = {0, 0, 0, 0};
 -   sp_get_samples_2d_common(sampler, s, t, p,
 -                            computeLambda, lodbias, rgba, faces);
 -}
 -
 -
 -static INLINE void
 -sp_get_samples_3d(const struct tgsi_sampler *tgsi_sampler,
 -                  const float s[QUAD_SIZE],
 -                  const float t[QUAD_SIZE],
 -                  const float p[QUAD_SIZE],
 -                  boolean computeLambda,
 -                  float lodbias,
 -                  float rgba[NUM_CHANNELS][QUAD_SIZE])
 +static void
 +img_filter_3d_nearest(struct tgsi_sampler *tgsi_sampler,
 +                      const float s[QUAD_SIZE],
 +                      const float t[QUAD_SIZE],
 +                      const float p[QUAD_SIZE],
 +                      float lodbias,
 +                      float rgba[NUM_CHANNELS][QUAD_SIZE])
  {
 -   const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
 +   const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
     const struct pipe_texture *texture = samp->texture;
 -   const struct pipe_sampler_state *sampler = samp->sampler;
 -   /* get/map pipe_surfaces corresponding to 3D tex slices */
 -   unsigned level0, level1, j, imgFilter;
 +   unsigned level0, j;
     int width, height, depth;
 -   float levelBlend;
 -   const uint face = 0;
 -
 -   choose_mipmap_levels(texture, sampler, s, t, p, computeLambda, lodbias,
 -                        &level0, &level1, &levelBlend, &imgFilter);
 -
 -   assert(sampler->normalized_coords);
 +   int x[4], y[4], z[4];
  
 +   level0 = samp->level;
     width = texture->width[level0];
     height = texture->height[level0];
     depth = texture->depth[level0];
     assert(height > 0);
     assert(depth > 0);
  
 -   switch (imgFilter) {
 -   case PIPE_TEX_FILTER_NEAREST:
 -      {
 -         int x[4], y[4], z[4];
 -         nearest_texcoord_4(sampler->wrap_s, s, width, x);
 -         nearest_texcoord_4(sampler->wrap_t, t, height, y);
 -         nearest_texcoord_4(sampler->wrap_r, p, depth, z);
 -         for (j = 0; j < QUAD_SIZE; j++) {
 -            get_texel(tgsi_sampler, face, level0, x[j], y[j], z[j], rgba, j);
 -            if (level0 != level1) {
 -               /* get texels from second mipmap level and blend */
 -               float rgba2[4][4];
 -               unsigned c;
 -               x[j] /= 2;
 -               y[j] /= 2;
 -               z[j] /= 2;
 -               get_texel(tgsi_sampler, face, level1, x[j], y[j], z[j], rgba2, j);
 -               for (c = 0; c < NUM_CHANNELS; c++) {
 -                  rgba[c][j] = lerp(levelBlend, rgba2[c][j], rgba[c][j]);
 -               }
 -            }
 -         }
 -      }
 -      break;
 -   case PIPE_TEX_FILTER_LINEAR:
 -   case PIPE_TEX_FILTER_ANISO:
 -      {
 -         int x0[4], x1[4], y0[4], y1[4], z0[4], z1[4];
 -         float xw[4], yw[4], zw[4]; /* interpolation weights */
 -         linear_texcoord_4(sampler->wrap_s, s, width,  x0, x1, xw);
 -         linear_texcoord_4(sampler->wrap_t, t, height, y0, y1, yw);
 -         linear_texcoord_4(sampler->wrap_r, p, depth,  z0, z1, zw);
 -
 -         for (j = 0; j < QUAD_SIZE; j++) {
 -            int c;
 -            float tx0[4][4], tx1[4][4];
 -            get_texel(tgsi_sampler, face, level0, x0[j], y0[j], z0[j], tx0, 0);
 -            get_texel(tgsi_sampler, face, level0, x1[j], y0[j], z0[j], tx0, 1);
 -            get_texel(tgsi_sampler, face, level0, x0[j], y1[j], z0[j], tx0, 2);
 -            get_texel(tgsi_sampler, face, level0, x1[j], y1[j], z0[j], tx0, 3);
 -            get_texel(tgsi_sampler, face, level0, x0[j], y0[j], z1[j], tx1, 0);
 -            get_texel(tgsi_sampler, face, level0, x1[j], y0[j], z1[j], tx1, 1);
 -            get_texel(tgsi_sampler, face, level0, x0[j], y1[j], z1[j], tx1, 2);
 -            get_texel(tgsi_sampler, face, level0, x1[j], y1[j], z1[j], tx1, 3);
 -
 -            /* interpolate R, G, B, A */
 -            for (c = 0; c < 4; c++) {
 -               rgba[c][j] = lerp_3d(xw[j], yw[j], zw[j],
 -                                    tx0[c][0], tx0[c][1],
 -                                    tx0[c][2], tx0[c][3],
 -                                    tx1[c][0], tx1[c][1],
 -                                    tx1[c][2], tx1[c][3]);
 -            }
 -
 -            if (level0 != level1) {
 -               /* get texels from second mipmap level and blend */
 -               float rgba2[4][4];
 -               x0[j] /= 2;
 -               y0[j] /= 2;
 -               z0[j] /= 2;
 -               x1[j] /= 2;
 -               y1[j] /= 2;
 -               z1[j] /= 2;
 -               get_texel(tgsi_sampler, face, level1, x0[j], y0[j], z0[j], tx0, 0);
 -               get_texel(tgsi_sampler, face, level1, x1[j], y0[j], z0[j], tx0, 1);
 -               get_texel(tgsi_sampler, face, level1, x0[j], y1[j], z0[j], tx0, 2);
 -               get_texel(tgsi_sampler, face, level1, x1[j], y1[j], z0[j], tx0, 3);
 -               get_texel(tgsi_sampler, face, level1, x0[j], y0[j], z1[j], tx1, 0);
 -               get_texel(tgsi_sampler, face, level1, x1[j], y0[j], z1[j], tx1, 1);
 -               get_texel(tgsi_sampler, face, level1, x0[j], y1[j], z1[j], tx1, 2);
 -               get_texel(tgsi_sampler, face, level1, x1[j], y1[j], z1[j], tx1, 3);
 -
 -               /* interpolate R, G, B, A */
 -               for (c = 0; c < 4; c++) {
 -                  rgba2[c][j] = lerp_3d(xw[j], yw[j], zw[j],
 -                                        tx0[c][0], tx0[c][1],
 -                                        tx0[c][2], tx0[c][3],
 -                                        tx1[c][0], tx1[c][1],
 -                                        tx1[c][2], tx1[c][3]);
 -               }
 -
 -               /* blend mipmap levels */
 -               for (c = 0; c < NUM_CHANNELS; c++) {
 -                  rgba[c][j] = lerp(levelBlend, rgba[c][j], rgba2[c][j]);
 -               }
 -            }
 -         }
 -      }
 -      break;
 -   default:
 -      assert(0);
 -   }
 -}
 -
 +   samp->nearest_texcoord_s(s, width,  x);
 +   samp->nearest_texcoord_t(t, height, y);
 +   samp->nearest_texcoord_p(p, depth,  z);
  
 -static void
 -sp_get_samples_cube(const struct tgsi_sampler *sampler,
 -                    const float s[QUAD_SIZE],
 -                    const float t[QUAD_SIZE],
 -                    const float p[QUAD_SIZE],
 -                    boolean computeLambda,
 -                    float lodbias,
 -                    float rgba[NUM_CHANNELS][QUAD_SIZE])
 -{
 -   unsigned faces[QUAD_SIZE], j;
 -   float ssss[4], tttt[4];
     for (j = 0; j < QUAD_SIZE; j++) {
 -      faces[j] = choose_cube_face(s[j], t[j], p[j], ssss + j, tttt + j);
 +      get_texel(tgsi_sampler, 0, level0, x[j], y[j], z[j], rgba, j);
     }
 -   sp_get_samples_2d_common(sampler, ssss, tttt, NULL,
 -                            computeLambda, lodbias, rgba, faces);
  }
  
  
  static void
 -sp_get_samples_rect(const struct tgsi_sampler *tgsi_sampler,
 -                    const float s[QUAD_SIZE],
 -                    const float t[QUAD_SIZE],
 -                    const float p[QUAD_SIZE],
 -                    boolean computeLambda,
 -                    float lodbias,
 -                    float rgba[NUM_CHANNELS][QUAD_SIZE])
 +img_filter_1d_linear(struct tgsi_sampler *tgsi_sampler,
 +                     const float s[QUAD_SIZE],
 +                     const float t[QUAD_SIZE],
 +                     const float p[QUAD_SIZE],
 +                     float lodbias,
 +                     float rgba[NUM_CHANNELS][QUAD_SIZE])
  {
 -   const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
 +   const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
     const struct pipe_texture *texture = samp->texture;
 -   const struct pipe_sampler_state *sampler = samp->sampler;
 -   const uint face = 0;
 -   unsigned level0, level1, j, imgFilter;
 -   int width, height;
 -   float levelBlend;
 +   unsigned level0, j;
 +   int width;
 +   int x0[4], x1[4];
 +   float xw[4]; /* weights */
  
 -   choose_mipmap_levels(texture, sampler, s, t, p, computeLambda, lodbias,
 -                        &level0, &level1, &levelBlend, &imgFilter);
 -
 -   /* texture RECTS cannot be mipmapped */
 -   assert(level0 == level1);
  
 +   level0 = samp->level;
     width = texture->width[level0];
 -   height = texture->height[level0];
  
     assert(width > 0);
  
 -   switch (imgFilter) {
 -   case PIPE_TEX_FILTER_NEAREST:
 -      {
 -         int x[4], y[4];
 -         nearest_texcoord_unnorm_4(sampler->wrap_s, s, width, x);
 -         nearest_texcoord_unnorm_4(sampler->wrap_t, t, height, y);
 -         for (j = 0; j < QUAD_SIZE; j++) {
 -            get_texel(tgsi_sampler, face, level0, x[j], y[j], 0, rgba, j);
 -            if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
 -               shadow_compare(sampler, rgba, p, j);
 -            }
 +   samp->linear_texcoord_s(s, width, x0, x1, xw);
 +
 +
 +   for (j = 0; j < QUAD_SIZE; j++) {
 +      float tx[4][4]; /* texels */
 +      int c;
 +      get_texel(tgsi_sampler, 0, level0, x0[j], 0, 0, tx, 0);
 +      get_texel(tgsi_sampler, 0, level0, x1[j], 0, 0, tx, 1);
 +
 +      /* interpolate R, G, B, A */
 +      for (c = 0; c < 4; c++) {
 +         rgba[c][j] = lerp(xw[j], tx[c][0], tx[c][1]);
 +      }
 +   }
 +}
 +
 +static void
 +img_filter_2d_linear(struct tgsi_sampler *tgsi_sampler,
 +                     const float s[QUAD_SIZE],
 +                     const float t[QUAD_SIZE],
 +                     const float p[QUAD_SIZE],
 +                     float lodbias,
 +                     float rgba[NUM_CHANNELS][QUAD_SIZE])
 +{
 +   const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
 +   const struct pipe_texture *texture = samp->texture;
 +   const unsigned *faces = samp->faces; /* zero when not cube-mapping */
 +   unsigned level0, j;
 +   int width, height;
 +   int x0[4], y0[4], x1[4], y1[4];
 +   float xw[4], yw[4]; /* weights */
 +
 +
 +   level0 = samp->level;
 +   width = texture->width[level0];
 +   height = texture->height[level0];
 +
 +   assert(width > 0);
 +
 +   samp->linear_texcoord_s(s, width,  x0, x1, xw);
 +   samp->linear_texcoord_t(t, height, y0, y1, yw);
 +
 +   for (j = 0; j < QUAD_SIZE; j++) {
 +      float tx[4][4]; /* texels */
 +      int c;
 +      get_texel(tgsi_sampler, faces[j], level0, x0[j], y0[j], 0, tx, 0);
 +      get_texel(tgsi_sampler, faces[j], level0, x1[j], y0[j], 0, tx, 1);
 +      get_texel(tgsi_sampler, faces[j], level0, x0[j], y1[j], 0, tx, 2);
 +      get_texel(tgsi_sampler, faces[j], level0, x1[j], y1[j], 0, tx, 3);
 +
 +      /* interpolate R, G, B, A */
 +      for (c = 0; c < 4; c++) {
 +         rgba[c][j] = lerp_2d(xw[j], yw[j],
 +                              tx[c][0], tx[c][1],
 +                              tx[c][2], tx[c][3]);
 +      }
 +   }
 +}
 +
 +
 +static void
 +img_filter_3d_linear(struct tgsi_sampler *tgsi_sampler,
 +                     const float s[QUAD_SIZE],
 +                     const float t[QUAD_SIZE],
 +                     const float p[QUAD_SIZE],
 +                     float lodbias,
 +                     float rgba[NUM_CHANNELS][QUAD_SIZE])
 +{
 +   const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
 +   const struct pipe_texture *texture = samp->texture;
 +   unsigned level0, j;
 +   int width, height, depth;
 +   int x0[4], x1[4], y0[4], y1[4], z0[4], z1[4];
 +   float xw[4], yw[4], zw[4]; /* interpolation weights */
 +
 +   level0 = samp->level;
 +   width = texture->width[level0];
 +   height = texture->height[level0];
 +   depth = texture->depth[level0];
 +
 +   assert(width > 0);
 +   assert(height > 0);
 +   assert(depth > 0);
 +
 +   samp->linear_texcoord_s(s, width,  x0, x1, xw);
 +   samp->linear_texcoord_t(t, height, y0, y1, yw);
 +   samp->linear_texcoord_p(p, depth,  z0, z1, zw);
 +
 +   for (j = 0; j < QUAD_SIZE; j++) {
 +      float tx0[4][4], tx1[4][4];
 +      int c;
 +      
 +      get_texel(tgsi_sampler, 0, level0, x0[j], y0[j], z0[j], tx0, 0);
 +      get_texel(tgsi_sampler, 0, level0, x1[j], y0[j], z0[j], tx0, 1);
 +      get_texel(tgsi_sampler, 0, level0, x0[j], y1[j], z0[j], tx0, 2);
 +      get_texel(tgsi_sampler, 0, level0, x1[j], y1[j], z0[j], tx0, 3);
 +      get_texel(tgsi_sampler, 0, level0, x0[j], y0[j], z1[j], tx1, 0);
 +      get_texel(tgsi_sampler, 0, level0, x1[j], y0[j], z1[j], tx1, 1);
 +      get_texel(tgsi_sampler, 0, level0, x0[j], y1[j], z1[j], tx1, 2);
 +      get_texel(tgsi_sampler, 0, level0, x1[j], y1[j], z1[j], tx1, 3);
 +
 +      /* interpolate R, G, B, A */
 +      for (c = 0; c < 4; c++) {
 +         rgba[c][j] = lerp_3d(xw[j], yw[j], zw[j],
 +                              tx0[c][0], tx0[c][1],
 +                              tx0[c][2], tx0[c][3],
 +                              tx1[c][0], tx1[c][1],
 +                              tx1[c][2], tx1[c][3]);
 +      }
 +   }
 +}
 +
 +
 +
 +
 +
 +
 +
 +static void
 +mip_filter_linear(struct tgsi_sampler *tgsi_sampler,
 +                     const float s[QUAD_SIZE],
 +                     const float t[QUAD_SIZE],
 +                     const float p[QUAD_SIZE],
 +                     float lodbias,
 +                     float rgba[NUM_CHANNELS][QUAD_SIZE])
 +{
 +   struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
 +   const struct pipe_texture *texture = samp->texture;
 +   int level0;
 +   float lambda;
 +
 +   lambda = samp->compute_lambda(samp, s, t, p, lodbias);
 +   level0 = (int)lambda;
 +
 +   if (lambda < 0.0) { 
 +      samp->level = 0;
 +      samp->mag_img_filter( tgsi_sampler, s, t, p, 0, rgba );
 +   }
 +   else if (level0 >= texture->last_level) {
 +      samp->level = texture->last_level;
 +      samp->min_img_filter( tgsi_sampler, s, t, p, 0, rgba );
 +   }
 +   else {
 +      float levelBlend = lambda - level0;
 +      float rgba0[4][4];
 +      float rgba1[4][4];
 +      int c,j;
 +
 +      samp->level = level0;
 +      samp->min_img_filter( tgsi_sampler, s, t, p, 0, rgba0 );
 +
 +      samp->level = level0+1;
 +      samp->min_img_filter( tgsi_sampler, s, t, p, 0, rgba1 );
 +
 +      for (j = 0; j < QUAD_SIZE; j++) {
 +         for (c = 0; c < 4; c++) {
 +            rgba[c][j] = lerp(levelBlend, rgba0[c][j], rgba1[c][j]);
           }
        }
 -      break;
 -   case PIPE_TEX_FILTER_LINEAR:
 -   case PIPE_TEX_FILTER_ANISO:
 -      {
 -         int x0[4], y0[4], x1[4], y1[4];
 -         float xw[4], yw[4]; /* weights */
 -         linear_texcoord_unnorm_4(sampler->wrap_s, s, width,  x0, x1, xw);
 -         linear_texcoord_unnorm_4(sampler->wrap_t, t, height, y0, y1, yw);
 -         for (j = 0; j < QUAD_SIZE; j++) {
 -            float tx[4][4]; /* texels */
 -            int c;
 -            get_texel(tgsi_sampler, face, level0, x0[j], y0[j], 0, tx, 0);
 -            get_texel(tgsi_sampler, face, level0, x1[j], y0[j], 0, tx, 1);
 -            get_texel(tgsi_sampler, face, level0, x0[j], y1[j], 0, tx, 2);
 -            get_texel(tgsi_sampler, face, level0, x1[j], y1[j], 0, tx, 3);
 -            if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
 -               shadow_compare4(sampler, tx, p);
 -            }
 -            for (c = 0; c < 4; c++) {
 -               rgba[c][j] = lerp_2d(xw[j], yw[j],
 -                                    tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
 -            }
 +   }
 +}
 +
 +
 +
 +static void
 +mip_filter_nearest(struct tgsi_sampler *tgsi_sampler,
 +                   const float s[QUAD_SIZE],
 +                   const float t[QUAD_SIZE],
 +                   const float p[QUAD_SIZE],
 +                   float lodbias,
 +                   float rgba[NUM_CHANNELS][QUAD_SIZE])
 +{
 +   struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
 +   const struct pipe_texture *texture = samp->texture;
 +   float lambda;
 +
 +   lambda = samp->compute_lambda(samp, s, t, p, lodbias);
 +
 +   if (lambda < 0.0) { 
 +      samp->level = 0;
 +      samp->mag_img_filter( tgsi_sampler, s, t, p, 0, rgba );
 +   }
 +   else {
 +      samp->level = (int)(lambda + 0.5) ;
 +      samp->level = MIN2(samp->level, (int)texture->last_level);
 +      samp->min_img_filter( tgsi_sampler, s, t, p, 0, rgba );
 +   }
 +}
 +
 +
 +static void
 +mip_filter_none(struct tgsi_sampler *tgsi_sampler,
 +                const float s[QUAD_SIZE],
 +                const float t[QUAD_SIZE],
 +                const float p[QUAD_SIZE],
 +                float lodbias,
 +                float rgba[NUM_CHANNELS][QUAD_SIZE])
 +{
 +   struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
 +   float lambda = samp->compute_lambda(samp, s, t, p, lodbias);
 +
 +   if (lambda < 0.0) { 
 +      samp->mag_img_filter( tgsi_sampler, s, t, p, 0, rgba );
 +   }
 +   else {
 +      samp->min_img_filter( tgsi_sampler, s, t, p, 0, rgba );
 +   }
 +}
 +
 +
 +
 +/* Specialized version of mip_filter_linear with hard-wired calls to
 + * 2d lambda calculation and 2d_linear_repeat_POT img filters.
 + */
 +static void
 +mip_filter_linear_2d_linear_repeat_POT(
 +   struct tgsi_sampler *tgsi_sampler,
 +   const float s[QUAD_SIZE],
 +   const float t[QUAD_SIZE],
 +   const float p[QUAD_SIZE],
 +   float lodbias,
 +   float rgba[NUM_CHANNELS][QUAD_SIZE])
 +{
 +   struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
 +   const struct pipe_texture *texture = samp->texture;
 +   int level0;
 +   float lambda;
 +
 +   lambda = compute_lambda_2d(samp, s, t, p, lodbias);
 +   level0 = (int)lambda;
 +
 +   /* Catches both negative and large values of level0:
 +    */
 +   if ((unsigned)level0 >= texture->last_level) { 
 +      if (level0 < 0)
 +         samp->level = 0;
 +      else
 +         samp->level = texture->last_level;
 +
 +      img_filter_2d_linear_repeat_POT( tgsi_sampler, s, t, p, 0, rgba );
 +   }
 +   else {
 +      float levelBlend = lambda - level0;
 +      float rgba0[4][4];
 +      float rgba1[4][4];
 +      int c,j;
 +
 +      samp->level = level0;
 +      img_filter_2d_linear_repeat_POT( tgsi_sampler, s, t, p, 0, rgba0 );
 +
 +      samp->level = level0+1;
 +      img_filter_2d_linear_repeat_POT( tgsi_sampler, s, t, p, 0, rgba1 );
 +
 +      for (j = 0; j < QUAD_SIZE; j++) {
 +         for (c = 0; c < 4; c++) {
 +            rgba[c][j] = lerp(levelBlend, rgba0[c][j], rgba1[c][j]);
           }
        }
 -      break;
 -   default:
 -      assert(0);
     }
  }
  
  
 -/**
 - * Common code for vertex/fragment program texture sampling.
 +
 +/* Compare stage in the little sampling pipeline.
   */
 -static INLINE void
 -sp_get_samples(struct tgsi_sampler *tgsi_sampler,
 +static void
 +sample_compare(struct tgsi_sampler *tgsi_sampler,
                 const float s[QUAD_SIZE],
                 const float t[QUAD_SIZE],
                 const float p[QUAD_SIZE],
 -               boolean computeLambda,
                 float lodbias,
                 float rgba[NUM_CHANNELS][QUAD_SIZE])
  {
 -   const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
 -   const struct pipe_texture *texture = samp->texture;
 +   struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
     const struct pipe_sampler_state *sampler = samp->sampler;
 +   int j, k0, k1, k2, k3;
 +   float val;
  
 -   if (!texture)
 -      return;
 +   samp->mip_filter( tgsi_sampler, s, t, p, lodbias, rgba );
  
 -   switch (texture->target) {
 -   case PIPE_TEXTURE_1D:
 -      assert(sampler->normalized_coords);
 -      sp_get_samples_1d(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba);
 +
 +   /**
 +    * Compare texcoord 'p' (aka R) against texture value 'rgba[0]'
 +    * When we sampled the depth texture, the depth value was put into all
 +    * RGBA channels.  We look at the red channel here.
 +    */
 +
 +   /* compare four texcoords vs. four texture samples */
 +   switch (sampler->compare_func) {
 +   case PIPE_FUNC_LESS:
 +      k0 = p[0] < rgba[0][0];
 +      k1 = p[1] < rgba[0][1];
 +      k2 = p[2] < rgba[0][2];
 +      k3 = p[3] < rgba[0][3];
        break;
 -   case PIPE_TEXTURE_2D:
 -      if (sampler->normalized_coords)
 -         sp_get_samples_2d(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba);
 -      else
 -         sp_get_samples_rect(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba);
 +   case PIPE_FUNC_LEQUAL:
 +      k0 = p[0] <= rgba[0][0];
 +      k1 = p[1] <= rgba[0][1];
 +      k2 = p[2] <= rgba[0][2];
 +      k3 = p[3] <= rgba[0][3];
        break;
 -   case PIPE_TEXTURE_3D:
 -      assert(sampler->normalized_coords);
 -      sp_get_samples_3d(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba);
 +   case PIPE_FUNC_GREATER:
 +      k0 = p[0] > rgba[0][0];
 +      k1 = p[1] > rgba[0][1];
 +      k2 = p[2] > rgba[0][2];
 +      k3 = p[3] > rgba[0][3];
        break;
 -   case PIPE_TEXTURE_CUBE:
 -      assert(sampler->normalized_coords);
 -      sp_get_samples_cube(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba);
 +   case PIPE_FUNC_GEQUAL:
 +      k0 = p[0] >= rgba[0][0];
 +      k1 = p[1] >= rgba[0][1];
 +      k2 = p[2] >= rgba[0][2];
 +      k3 = p[3] >= rgba[0][3];
 +      break;
 +   case PIPE_FUNC_EQUAL:
 +      k0 = p[0] == rgba[0][0];
 +      k1 = p[1] == rgba[0][1];
 +      k2 = p[2] == rgba[0][2];
 +      k3 = p[3] == rgba[0][3];
 +      break;
 +   case PIPE_FUNC_NOTEQUAL:
 +      k0 = p[0] != rgba[0][0];
 +      k1 = p[1] != rgba[0][1];
 +      k2 = p[2] != rgba[0][2];
 +      k3 = p[3] != rgba[0][3];
 +      break;
 +   case PIPE_FUNC_ALWAYS:
 +      k0 = k1 = k2 = k3 = 1;
 +      break;
 +   case PIPE_FUNC_NEVER:
 +      k0 = k1 = k2 = k3 = 0;
        break;
     default:
 +      k0 = k1 = k2 = k3 = 0;
        assert(0);
 +      break;
     }
  
 -#if 0 /* DEBUG */
 -   {
 -      int i;
 -      printf("Sampled at %f, %f, %f:\n", s[0], t[0], p[0]);
 -      for (i = 0; i < 4; i++) {
 -         printf("Frag %d: %f %f %f %f\n", i,
 -                rgba[0][i],
 -                rgba[1][i],
 -                rgba[2][i],
 -                rgba[3][i]);
 -      }
 +   /* convert four pass/fail values to an intensity in [0,1] */
 +   val = 0.25F * (k0 + k1 + k2 + k3);
 +
 +   /* XXX returning result for default GL_DEPTH_TEXTURE_MODE = GL_LUMINANCE */
 +   for (j = 0; j < 4; j++) {
 +      rgba[0][j] = rgba[1][j] = rgba[2][j] = val;
 +      rgba[3][j] = 1.0F;
     }
 -#endif
  }
  
 +/* Calculate cube faces.
 + */
  static void
 -sp_get_samples_fallback(struct tgsi_sampler *tgsi_sampler,
 -                        const float s[QUAD_SIZE],
 -                        const float t[QUAD_SIZE],
 -                        const float p[QUAD_SIZE],
 -                        float lodbias,
 -                        float rgba[NUM_CHANNELS][QUAD_SIZE])
 +sample_cube(struct tgsi_sampler *tgsi_sampler,
 +            const float s[QUAD_SIZE],
 +            const float t[QUAD_SIZE],
 +            const float p[QUAD_SIZE],
 +            float lodbias,
 +            float rgba[NUM_CHANNELS][QUAD_SIZE])
  {
 -   sp_get_samples(tgsi_sampler, s, t, p, TRUE, lodbias, rgba);
 +   struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
 +   unsigned j;
 +   float ssss[4], tttt[4];
 +
 +   /*
 +     major axis
 +     direction     target                             sc     tc    ma
 +     ----------    -------------------------------    ---    ---   ---
 +     +rx          TEXTURE_CUBE_MAP_POSITIVE_X_EXT    -rz    -ry   rx
 +     -rx          TEXTURE_CUBE_MAP_NEGATIVE_X_EXT    +rz    -ry   rx
 +     +ry          TEXTURE_CUBE_MAP_POSITIVE_Y_EXT    +rx    +rz   ry
 +     -ry          TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT    +rx    -rz   ry
 +     +rz          TEXTURE_CUBE_MAP_POSITIVE_Z_EXT    +rx    -ry   rz
 +     -rz          TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT    -rx    -ry   rz
 +   */
 +   for (j = 0; j < QUAD_SIZE; j++) {
 +      float rx = s[j];
 +      float ry = t[j];
 +      float rz = p[j];
 +      const float arx = fabsf(rx), ary = fabsf(ry), arz = fabsf(rz);
 +      unsigned face;
 +      float sc, tc, ma;
 +
 +      if (arx > ary && arx > arz) {
 +         if (rx >= 0.0F) {
 +            face = PIPE_TEX_FACE_POS_X;
 +            sc = -rz;
 +            tc = -ry;
 +            ma = arx;
 +         }
 +         else {
 +            face = PIPE_TEX_FACE_NEG_X;
 +            sc = rz;
 +            tc = -ry;
 +            ma = arx;
 +         }
 +      }
 +      else if (ary > arx && ary > arz) {
 +         if (ry >= 0.0F) {
 +            face = PIPE_TEX_FACE_POS_Y;
 +            sc = rx;
 +            tc = rz;
 +            ma = ary;
 +         }
 +         else {
 +            face = PIPE_TEX_FACE_NEG_Y;
 +            sc = rx;
 +            tc = -rz;
 +            ma = ary;
 +         }
 +      }
 +      else {
 +         if (rz > 0.0F) {
 +            face = PIPE_TEX_FACE_POS_Z;
 +            sc = rx;
 +            tc = -ry;
 +            ma = arz;
 +         }
 +         else {
 +            face = PIPE_TEX_FACE_NEG_Z;
 +            sc = -rx;
 +            tc = -ry;
 +            ma = arz;
 +         }
 +      }
 +
 +      ssss[j] = ( sc / ma + 1.0F ) * 0.5F;
 +      tttt[j] = ( tc / ma + 1.0F ) * 0.5F;
 +      samp->faces[j] = face;
 +   }
 +
 +   /* In our little pipeline, the compare stage is next.  If compare
 +    * is not active, this will point somewhere deeper into the
 +    * pipeline, eg. to mip_filter or even img_filter.
 +    */
 +   samp->compare(tgsi_sampler, ssss, tttt, NULL, lodbias, rgba);
  }
  
 -/**
 - * Called via tgsi_sampler::get_samples() when running a fragment shader.
 - * Get four filtered RGBA values from the sampler's texture.
 - */
 -void
 -sp_get_samples_fragment(struct tgsi_sampler *tgsi_sampler,
 -                        const float s[QUAD_SIZE],
 -                        const float t[QUAD_SIZE],
 -                        const float p[QUAD_SIZE],
 -                        float lodbias,
 -                        float rgba[NUM_CHANNELS][QUAD_SIZE])
 +
 +
 +
 +static wrap_nearest_func get_nearest_unorm_wrap( unsigned mode )
  {
 -   struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
 -   const struct pipe_texture *texture = samp->texture;
 -   const struct pipe_sampler_state *sampler = samp->sampler;
 +   switch (mode) {
 +   case PIPE_TEX_WRAP_CLAMP:
 +      return wrap_nearest_unorm_clamp;
 +   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
 +   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
 +      return wrap_nearest_unorm_clamp_to_border;
 +   default:
 +      assert(0);
 +      return wrap_nearest_unorm_clamp;
 +   }
 +}
  
 -   tgsi_sampler->get_samples = sp_get_samples_fallback;
  
 -   /* Try to hook in a faster sampler.  Ultimately we'll have to
 -    * code-generate these.  Luckily most of this looks like it is
 -    * orthogonal state within the sampler.
 -    */
 -   if (texture->target == PIPE_TEXTURE_2D &&
 -       sampler->min_img_filter == sampler->mag_img_filter &&
 -       sampler->wrap_s == sampler->wrap_t &&
 -       sampler->compare_mode == FALSE &&
 -       sampler->normalized_coords) 
 -   {
 -      samp->xpot = util_unsigned_logbase2( samp->texture->width[0] );
 -      samp->ypot = util_unsigned_logbase2( samp->texture->height[0] );
 -
 -      if (sampler->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) {
 -         samp->level = CLAMP((int) sampler->min_lod,
 -                             0, (int) texture->last_level);
 -
 -         if (sampler->wrap_s == PIPE_TEX_WRAP_REPEAT) {
 -            switch (sampler->min_img_filter) {
 +static wrap_nearest_func get_nearest_wrap( unsigned mode )
 +{
 +   switch (mode) {
 +   case PIPE_TEX_WRAP_REPEAT:
 +      return wrap_nearest_repeat;
 +   case PIPE_TEX_WRAP_CLAMP:
 +      return wrap_nearest_clamp;
 +   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
 +      return wrap_nearest_clamp_to_edge;
 +   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
 +      return wrap_nearest_clamp_to_border;
 +   case PIPE_TEX_WRAP_MIRROR_REPEAT:
 +      return wrap_nearest_mirror_repeat;
 +   case PIPE_TEX_WRAP_MIRROR_CLAMP:
 +      return wrap_nearest_mirror_clamp;
 +   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
 +      return wrap_nearest_mirror_clamp_to_edge;
 +   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
 +      return wrap_nearest_mirror_clamp_to_border;
 +   default:
 +      assert(0);
 +      return wrap_nearest_repeat;
 +   }
 +}
 +
 +static wrap_linear_func get_linear_unorm_wrap( unsigned mode )
 +{
 +   switch (mode) {
 +   case PIPE_TEX_WRAP_CLAMP:
 +      return wrap_linear_unorm_clamp;
 +   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
 +   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
 +      return wrap_linear_unorm_clamp_to_border;
 +   default:
 +      assert(0);
 +      return wrap_linear_unorm_clamp;
 +   }
 +}
 +
 +static wrap_linear_func get_linear_wrap( unsigned mode )
 +{
 +   switch (mode) {
 +   case PIPE_TEX_WRAP_REPEAT:
 +      return wrap_linear_repeat;
 +   case PIPE_TEX_WRAP_CLAMP:
 +      return wrap_linear_clamp;
 +   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
 +      return wrap_linear_clamp_to_edge;
 +   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
 +      return wrap_linear_clamp_to_border;
 +   case PIPE_TEX_WRAP_MIRROR_REPEAT:
 +      return wrap_linear_mirror_repeat;
 +   case PIPE_TEX_WRAP_MIRROR_CLAMP:
 +      return wrap_linear_mirror_clamp;
 +   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
 +      return wrap_linear_mirror_clamp_to_edge;
 +   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
 +      return wrap_linear_mirror_clamp_to_border;
 +   default:
 +      assert(0);
 +      return wrap_linear_repeat;
 +   }
 +}
 +
 +static compute_lambda_func get_lambda_func( const union sp_sampler_key key )
 +{
 +   if (key.bits.processor == TGSI_PROCESSOR_VERTEX)
 +      return compute_lambda_vert;
 +   
 +   switch (key.bits.target) {
 +   case PIPE_TEXTURE_1D:
 +      return compute_lambda_1d;
 +   case PIPE_TEXTURE_2D:
 +   case PIPE_TEXTURE_CUBE:
 +      return compute_lambda_2d;
 +   case PIPE_TEXTURE_3D:
 +      return compute_lambda_3d;
 +   default:
 +      assert(0);
 +      return compute_lambda_1d;
 +   }
 +}
 +
 +static filter_func get_img_filter( const union sp_sampler_key key,
 +                                   unsigned filter,
 +                                   const struct pipe_sampler_state *sampler )
 +{
 +   switch (key.bits.target) {
 +   case PIPE_TEXTURE_1D:
 +      if (filter == PIPE_TEX_FILTER_NEAREST) 
 +         return img_filter_1d_nearest;
 +      else
 +         return img_filter_1d_linear;
 +      break;
 +   case PIPE_TEXTURE_2D:
 +      /* Try for fast path:
 +       */
 +      if (key.bits.is_pot &&
 +          sampler->wrap_s == sampler->wrap_t &&
 +          sampler->normalized_coords) 
 +      {
 +         switch (sampler->wrap_s) {
 +         case PIPE_TEX_WRAP_REPEAT:
 +            switch (filter) {
              case PIPE_TEX_FILTER_NEAREST:
 -               tgsi_sampler->get_samples = sp_get_samples_2d_nearest_repeat_POT;
 -               break;
 +               return img_filter_2d_nearest_repeat_POT;
              case PIPE_TEX_FILTER_LINEAR:
 -               tgsi_sampler->get_samples = sp_get_samples_2d_linear_repeat_POT;
 -               break;
 +               return img_filter_2d_linear_repeat_POT;
              default:
                 break;
              }
 -         } 
 -         else if (sampler->wrap_s == PIPE_TEX_WRAP_CLAMP) {
 -            switch (sampler->min_img_filter) {
 +            break;
 +         case PIPE_TEX_WRAP_CLAMP:
 +            switch (filter) {
              case PIPE_TEX_FILTER_NEAREST:
 -               tgsi_sampler->get_samples = sp_get_samples_2d_nearest_clamp_POT;
 -               break;
 +               return img_filter_2d_nearest_clamp_POT;
              default:
                 break;
              }
           }
        }
 -      else if (sampler->min_mip_filter == PIPE_TEX_MIPFILTER_LINEAR) {
 -         if (sampler->wrap_s == PIPE_TEX_WRAP_REPEAT) {
 -            switch (sampler->min_img_filter) {
 -            case PIPE_TEX_FILTER_LINEAR:
 -               /* This one not working yet:
 -                */
 -               if (0)
 -                  tgsi_sampler->get_samples = sp_get_samples_2d_linear_mip_linear_repeat_POT;
 -               break;
 -            default:
 -               break;
 -            }
 -         } 
 -      }
 -   }
 -   else if (0) {
 -      _debug_printf("target %d/%d min_mip %d/%d min_img %d/%d wrap %d/%d compare %d/%d norm %d/%d\n",
 -                    texture->target, PIPE_TEXTURE_2D,
 -                    sampler->min_mip_filter, PIPE_TEX_MIPFILTER_NONE,
 -                    sampler->min_img_filter, sampler->mag_img_filter,
 -                    sampler->wrap_s, sampler->wrap_t,
 -                    sampler->compare_mode, FALSE,
 -                    sampler->normalized_coords, TRUE);
 +      /* Fallthrough to default versions:
 +       */
 +   case PIPE_TEXTURE_CUBE:
 +      if (filter == PIPE_TEX_FILTER_NEAREST) 
 +         return img_filter_2d_nearest;
 +      else
 +         return img_filter_2d_linear;
 +      break;
 +   case PIPE_TEXTURE_3D:
 +      if (filter == PIPE_TEX_FILTER_NEAREST) 
 +         return img_filter_3d_nearest;
 +      else
 +         return img_filter_3d_linear;
 +      break;
 +   default:
 +      assert(0);
 +      return img_filter_1d_nearest;
     }
 -
 -   tgsi_sampler->get_samples( tgsi_sampler, s, t, p, lodbias, rgba );
  }
  
  
  /**
 - * Called via tgsi_sampler::get_samples() when running a vertex shader.
 - * Get four filtered RGBA values from the sampler's texture.
 + * Bind the given texture object and texture cache to the sampler varient.
   */
  void
 -sp_get_samples_vertex(struct tgsi_sampler *tgsi_sampler,
 -                      const float s[QUAD_SIZE],
 -                      const float t[QUAD_SIZE],
 -                      const float p[QUAD_SIZE],
 -                      float lodbias,
 -                      float rgba[NUM_CHANNELS][QUAD_SIZE])
 +sp_sampler_varient_bind_texture( struct sp_sampler_varient *samp,
-                                  struct softpipe_tile_cache *tex_cache,
++                                 struct softpipe_tex_tile_cache *tex_cache,
 +                                 const struct pipe_texture *texture )
 +{
 +   const struct pipe_sampler_state *sampler = samp->sampler;
 +
 +   samp->texture = texture;
 +   samp->cache = tex_cache;
 +   samp->xpot = util_unsigned_logbase2( texture->width[0] );
 +   samp->ypot = util_unsigned_logbase2( texture->height[0] );
 +   samp->level = CLAMP((int) sampler->min_lod, 0, (int) texture->last_level);
 +}
 +
 +
 +void
 +sp_sampler_varient_destroy( struct sp_sampler_varient *samp )
  {
 -   sp_get_samples(tgsi_sampler, s, t, p, FALSE, lodbias, rgba);
 +   FREE(samp);
 +}
 +
 +
 +/* Create a sampler varient for a given set of non-orthogonal state.  Currently the 
 + */
 +struct sp_sampler_varient *
 +sp_create_sampler_varient( const struct pipe_sampler_state *sampler,
 +                           const union sp_sampler_key key )
 +{
 +   struct sp_sampler_varient *samp = CALLOC_STRUCT(sp_sampler_varient);
 +   if (!samp)
 +      return NULL;
 +
 +   samp->sampler = sampler;
 +   samp->key = key;
 +
 +   /* Note that (for instance) linear_texcoord_s and
 +    * nearest_texcoord_s may be active at the same time, if the
 +    * sampler min_img_filter differs from its mag_img_filter.
 +    */
 +   if (sampler->normalized_coords) {
 +      samp->linear_texcoord_s = get_linear_wrap( sampler->wrap_s );
 +      samp->linear_texcoord_t = get_linear_wrap( sampler->wrap_t );
 +      samp->linear_texcoord_p = get_linear_wrap( sampler->wrap_r );
 +      
 +      samp->nearest_texcoord_s = get_nearest_wrap( sampler->wrap_s );
 +      samp->nearest_texcoord_t = get_nearest_wrap( sampler->wrap_t );
 +      samp->nearest_texcoord_p = get_nearest_wrap( sampler->wrap_r );
 +   }
 +   else {
 +      samp->linear_texcoord_s = get_linear_unorm_wrap( sampler->wrap_s );
 +      samp->linear_texcoord_t = get_linear_unorm_wrap( sampler->wrap_t );
 +      samp->linear_texcoord_p = get_linear_unorm_wrap( sampler->wrap_r );
 +      
 +      samp->nearest_texcoord_s = get_nearest_unorm_wrap( sampler->wrap_s );
 +      samp->nearest_texcoord_t = get_nearest_unorm_wrap( sampler->wrap_t );
 +      samp->nearest_texcoord_p = get_nearest_unorm_wrap( sampler->wrap_r );
 +   }
 +   
 +   samp->compute_lambda = get_lambda_func( key );
 +
 +   samp->min_img_filter = get_img_filter(key, sampler->min_img_filter, sampler);
 +   samp->mag_img_filter = get_img_filter(key, sampler->mag_img_filter, sampler);
 +
 +   switch (sampler->min_mip_filter) {
 +   case PIPE_TEX_MIPFILTER_NONE:
 +      if (sampler->min_img_filter == sampler->mag_img_filter) 
 +         samp->mip_filter = samp->min_img_filter;         
 +      else
 +         samp->mip_filter = mip_filter_none;
 +      break;
 +
 +   case PIPE_TEX_MIPFILTER_NEAREST:
 +      samp->mip_filter = mip_filter_nearest;
 +      break;
 +
 +   case PIPE_TEX_MIPFILTER_LINEAR:
 +      if (key.bits.is_pot &&
 +          sampler->min_img_filter == sampler->mag_img_filter &&
 +          sampler->normalized_coords &&
 +          sampler->wrap_s == PIPE_TEX_WRAP_REPEAT &&
 +          sampler->wrap_t == PIPE_TEX_WRAP_REPEAT &&
 +          sampler->min_img_filter == PIPE_TEX_FILTER_LINEAR)
 +      {
 +         samp->mip_filter = mip_filter_linear_2d_linear_repeat_POT;
 +      }
 +      else 
 +      {
 +         samp->mip_filter = mip_filter_linear;
 +      }
 +      break;
 +   }
 +
 +   if (sampler->compare_mode != FALSE) {
 +      samp->compare = sample_compare;
 +   }
 +   else {
 +      /* Skip compare operation by promoting the mip_filter function
 +       * pointer:
 +       */
 +      samp->compare = samp->mip_filter;
 +   }
 +   
 +   if (key.bits.target == PIPE_TEXTURE_CUBE) {
 +      samp->base.get_samples = sample_cube;
 +   }
 +   else {
 +      samp->faces[0] = 0;
 +      samp->faces[1] = 0;
 +      samp->faces[2] = 0;
 +      samp->faces[3] = 0;
 +
 +      /* Skip cube face determination by promoting the compare
 +       * function pointer:
 +       */
 +      samp->base.get_samples = samp->compare;
 +   }
 +
 +   return samp;
  }
 +
 +
 +
 +
 +
 +
index f6cd57ec0ac8073843ff0758e9fde405c6859899,1756d3a4ee3ce613e66a5bb7980f9fc54db5c26f..b0797711d374da0cf8abf251b9f420d549e35984
  
  #include "tgsi/tgsi_exec.h"
  
 +struct sp_sampler_varient;
 +
 +typedef void (*wrap_nearest_func)(const float s[4],
 +                                  unsigned size,
 +                                  int icoord[4]);
 +
 +typedef void (*wrap_linear_func)(const float s[4], 
 +                                 unsigned size,
 +                                 int icoord0[4],
 +                                 int icoord1[4],
 +                                 float w[4]);
 +
 +typedef float (*compute_lambda_func)(const struct sp_sampler_varient *sampler,
 +                                     const float s[QUAD_SIZE],
 +                                     const float t[QUAD_SIZE],
 +                                     const float p[QUAD_SIZE],
 +                                     float lodbias);
 +
 +typedef void (*filter_func)(struct tgsi_sampler *tgsi_sampler,
 +                            const float s[QUAD_SIZE],
 +                            const float t[QUAD_SIZE],
 +                            const float p[QUAD_SIZE],
 +                            float lodbias,
 +                            float rgba[NUM_CHANNELS][QUAD_SIZE]);
 +
 +
 +union sp_sampler_key {
 +   struct {
 +      unsigned target:3;
 +      unsigned is_pot:1;
 +      unsigned processor:2;
 +      unsigned unit:4;
 +      unsigned pad:22;
 +   } bits;
 +   unsigned value;
 +};
  
  /**
   * Subclass of tgsi_sampler
   */
 -struct sp_shader_sampler
 +struct sp_sampler_varient
  {
     struct tgsi_sampler base;  /**< base class */
  
-    struct softpipe_tile_cache *cache;
 +   union sp_sampler_key key;
 +
 +   /* The owner of this struct:
 +    */
 +   const struct pipe_sampler_state *sampler;
 +
 +
 +   /* Currently bound texture:
 +    */
 +   const struct pipe_texture *texture;
++   struct softpipe_tex_tile_cache *cache;
 +
 +   unsigned processor;
 +
     /* For sp_get_samples_2d_linear_POT:
      */
     unsigned xpot;
     unsigned ypot;
     unsigned level;
  
 -   const struct pipe_texture *texture;
 -   const struct pipe_sampler_state *sampler;
 +   unsigned faces[4];
 +   
 +   wrap_nearest_func nearest_texcoord_s;
 +   wrap_nearest_func nearest_texcoord_t;
 +   wrap_nearest_func nearest_texcoord_p;
  
 -   struct softpipe_tex_tile_cache *cache;
 +   wrap_linear_func linear_texcoord_s;
 +   wrap_linear_func linear_texcoord_t;
 +   wrap_linear_func linear_texcoord_p;
 +
 +   filter_func min_img_filter;
 +   filter_func mag_img_filter;
 +
 +   compute_lambda_func compute_lambda;
 +
 +   filter_func mip_filter;
 +   filter_func compare;
 +   
 +   /* Linked list:
 +    */
 +   struct sp_sampler_varient *next;
  };
  
 +struct sp_sampler;
  
 +/* Create a sampler varient for a given set of non-orthogonal state.  Currently the 
 + */
 +struct sp_sampler_varient *
 +sp_create_sampler_varient( const struct pipe_sampler_state *sampler,
 +                           const union sp_sampler_key key );
  
 -static INLINE struct sp_shader_sampler *
 -sp_shader_sampler(const struct tgsi_sampler *sampler)
 -{
 -   return (struct sp_shader_sampler *) sampler;
 -}
 +void sp_sampler_varient_bind_texture( struct sp_sampler_varient *varient,
-                                       struct softpipe_tile_cache *tex_cache,
++                                      struct softpipe_tex_tile_cache *tex_cache,
 +                                      const struct pipe_texture *tex );
  
 +void sp_sampler_varient_destroy( struct sp_sampler_varient * );
  
 -extern void
 -sp_get_samples_fragment(struct tgsi_sampler *tgsi_sampler,
 -                        const float s[QUAD_SIZE],
 -                        const float t[QUAD_SIZE],
 -                        const float p[QUAD_SIZE],
 -                        float lodbias,
 -                        float rgba[NUM_CHANNELS][QUAD_SIZE]);
 +
 +
 +static INLINE struct sp_sampler_varient *
 +sp_sampler_varient(const struct tgsi_sampler *sampler)
 +{
 +   return (struct sp_sampler_varient *) sampler;
 +}
  
  extern void
 -sp_get_samples_vertex(struct tgsi_sampler *tgsi_sampler,
 -                      const float s[QUAD_SIZE],
 -                      const float t[QUAD_SIZE],
 -                      const float p[QUAD_SIZE],
 -                      float lodbias,
 -                      float rgba[NUM_CHANNELS][QUAD_SIZE]);
 +sp_get_samples(struct tgsi_sampler *tgsi_sampler,
 +               const float s[QUAD_SIZE],
 +               const float t[QUAD_SIZE],
 +               const float p[QUAD_SIZE],
 +               float lodbias,
 +               float rgba[NUM_CHANNELS][QUAD_SIZE]);
  
  
  #endif /* SP_TEX_SAMPLE_H */
index 0000000000000000000000000000000000000000,c2dd68c7a2a19f70f6ecbe2607bfa602a309c1c0..407a22a9f4bd02c3c6bb857c137dae05d6ba67d7
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,274 +1,273 @@@
 -   if (tc->texture) {
 -      struct softpipe_texture *spt = softpipe_texture(tc->texture);
 -      if (spt->timestamp != tc->timestamp) {
 -         /* texture was modified, invalidate all cached tiles */
 -         uint i;
 -         _debug_printf("INV %d %d\n", tc->timestamp, spt->timestamp);
 -         for (i = 0; i < NUM_ENTRIES; i++) {
 -            tc->entries[i].addr.bits.invalid = 1;
 -         }
 -
 -         tc->timestamp = spt->timestamp;
 -      }
+ /**************************************************************************
+  * 
+  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+  * All Rights Reserved.
+  * 
+  * Permission is hereby granted, free of charge, to any person obtaining a
+  * copy of this software and associated documentation files (the
+  * "Software"), to deal in the Software without restriction, including
+  * without limitation the rights to use, copy, modify, merge, publish,
+  * distribute, sub license, and/or sell copies of the Software, and to
+  * permit persons to whom the Software is furnished to do so, subject to
+  * the following conditions:
+  * 
+  * The above copyright notice and this permission notice (including the
+  * next paragraph) shall be included in all copies or substantial portions
+  * of the Software.
+  * 
+  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+  * 
+  **************************************************************************/
+ /**
+  * Texture tile caching.
+  *
+  * Author:
+  *    Brian Paul
+  */
+ #include "pipe/p_inlines.h"
+ #include "util/u_memory.h"
+ #include "util/u_tile.h"
+ #include "sp_context.h"
+ #include "sp_surface.h"
+ #include "sp_texture.h"
+ #include "sp_tex_tile_cache.h"
+    
+ struct softpipe_tex_tile_cache *
+ sp_create_tex_tile_cache( struct pipe_screen *screen )
+ {
+    struct softpipe_tex_tile_cache *tc;
+    uint pos;
+    tc = CALLOC_STRUCT( softpipe_tex_tile_cache );
+    if (tc) {
+       tc->screen = screen;
+       for (pos = 0; pos < NUM_ENTRIES; pos++) {
+          tc->entries[pos].addr.bits.invalid = 1;
+       }
+       tc->last_tile = &tc->entries[0]; /* any tile */
+    }
+    return tc;
+ }
+ void
+ sp_destroy_tex_tile_cache(struct softpipe_tex_tile_cache *tc)
+ {
+    struct pipe_screen *screen;
+    uint pos;
+    for (pos = 0; pos < NUM_ENTRIES; pos++) {
+       /*assert(tc->entries[pos].x < 0);*/
+    }
+    if (tc->transfer) {
+       screen = tc->transfer->texture->screen;
+       screen->tex_transfer_destroy(tc->transfer);
+    }
+    if (tc->tex_trans) {
+       screen = tc->tex_trans->texture->screen;
+       screen->tex_transfer_destroy(tc->tex_trans);
+    }
+    FREE( tc );
+ }
+ void
+ sp_tex_tile_cache_map_transfers(struct softpipe_tex_tile_cache *tc)
+ {
+    if (tc->tex_trans && !tc->tex_trans_map)
+       tc->tex_trans_map = tc->screen->transfer_map(tc->screen, tc->tex_trans);
+ }
+ void
+ sp_tex_tile_cache_unmap_transfers(struct softpipe_tex_tile_cache *tc)
+ {
+    if (tc->tex_trans_map) {
+       tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
+       tc->tex_trans_map = NULL;
+    }
+ }
++/**
++ * Invalidate all cached tiles for the cached texture.
++ * Should be called when the texture is modified.
++ */
+ void
+ sp_tex_tile_cache_validate_texture(struct softpipe_tex_tile_cache *tc)
+ {
++   unsigned i;
++
++   assert(tc);
++   assert(tc->texture);
++
++   for (i = 0; i < NUM_ENTRIES; i++) {
++      tc->entries[i].addr.bits.invalid = 1;
+    }
+ }
+ /**
+  * Specify the texture to cache.
+  */
+ void
+ sp_tex_tile_cache_set_texture(struct softpipe_tex_tile_cache *tc,
+                           struct pipe_texture *texture)
+ {
+    uint i;
+    assert(!tc->transfer);
+    if (tc->texture != texture) {
+       pipe_texture_reference(&tc->texture, texture);
+       if (tc->tex_trans) {
+          struct pipe_screen *screen = tc->tex_trans->texture->screen;
+          
+          if (tc->tex_trans_map) {
+             screen->transfer_unmap(screen, tc->tex_trans);
+             tc->tex_trans_map = NULL;
+          }
+          screen->tex_transfer_destroy(tc->tex_trans);
+          tc->tex_trans = NULL;
+       }
+       /* mark as entries as invalid/empty */
+       /* XXX we should try to avoid this when the teximage hasn't changed */
+       for (i = 0; i < NUM_ENTRIES; i++) {
+          tc->entries[i].addr.bits.invalid = 1;
+       }
+       tc->tex_face = -1; /* any invalid value here */
+    }
+ }
+ /**
+  * Flush the tile cache: write all dirty tiles back to the transfer.
+  * any tiles "flagged" as cleared will be "really" cleared.
+  */
+ void
+ sp_flush_tex_tile_cache(struct softpipe_tex_tile_cache *tc)
+ {
+    int pos;
+    if (tc->texture) {
+       /* caching a texture, mark all entries as empty */
+       for (pos = 0; pos < NUM_ENTRIES; pos++) {
+          tc->entries[pos].addr.bits.invalid = 1;
+       }
+       tc->tex_face = -1;
+    }
+ }
+ /**
+  * Given the texture face, level, zslice, x and y values, compute
+  * the cache entry position/index where we'd hope to find the
+  * cached texture tile.
+  * This is basically a direct-map cache.
+  * XXX There's probably lots of ways in which we can improve this.
+  */
+ static INLINE uint
+ tex_cache_pos( union tex_tile_address addr )
+ {
+    uint entry = (addr.bits.x + 
+                  addr.bits.y * 9 + 
+                  addr.bits.z * 3 + 
+                  addr.bits.face + 
+                  addr.bits.level * 7);
+    return entry % NUM_ENTRIES;
+ }
+ /**
+  * Similar to sp_get_cached_tile() but for textures.
+  * Tiles are read-only and indexed with more params.
+  */
+ const struct softpipe_tex_cached_tile *
+ sp_find_cached_tile_tex(struct softpipe_tex_tile_cache *tc, 
+                         union tex_tile_address addr )
+ {
+    struct pipe_screen *screen = tc->screen;
+    struct softpipe_tex_cached_tile *tile;
+    
+    tile = tc->entries + tex_cache_pos( addr );
+    if (addr.value != tile->addr.value) {
+       /* cache miss.  Most misses are because we've invaldiated the
+        * texture cache previously -- most commonly on binding a new
+        * texture.  Currently we effectively flush the cache on texture
+        * bind.
+        */
+ #if 0
+       _debug_printf("miss at %u:  x=%d y=%d z=%d face=%d level=%d\n"
+                     "   tile %u:  x=%d y=%d z=%d face=%d level=%d\n",
+                     pos, x/TILE_SIZE, y/TILE_SIZE, z, face, level,
+                     pos, tile->addr.bits.x, tile->addr.bits.y, tile->z, tile->face, tile->level);
+ #endif
+       /* check if we need to get a new transfer */
+       if (!tc->tex_trans ||
+           tc->tex_face != addr.bits.face ||
+           tc->tex_level != addr.bits.level ||
+           tc->tex_z != addr.bits.z) {
+          /* get new transfer (view into texture) */
+          if (tc->tex_trans) {
+             if (tc->tex_trans_map) {
+                tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
+                tc->tex_trans_map = NULL;
+             }
+             screen->tex_transfer_destroy(tc->tex_trans);
+             tc->tex_trans = NULL;
+          }
+          tc->tex_trans = 
+             screen->get_tex_transfer(screen, tc->texture, 
+                                      addr.bits.face, 
+                                      addr.bits.level, 
+                                      addr.bits.z, 
+                                      PIPE_TRANSFER_READ, 0, 0,
+                                      tc->texture->width[addr.bits.level],
+                                      tc->texture->height[addr.bits.level]);
+          tc->tex_trans_map = screen->transfer_map(screen, tc->tex_trans);
+          tc->tex_face = addr.bits.face;
+          tc->tex_level = addr.bits.level;
+          tc->tex_z = addr.bits.z;
+       }
+       /* get tile from the transfer (view into texture) */
+       pipe_get_tile_rgba(tc->tex_trans,
+                          addr.bits.x * TILE_SIZE, 
+                          addr.bits.y * TILE_SIZE,
+                          TILE_SIZE, TILE_SIZE,
+                          (float *) tile->data.color);
+       tile->addr = addr;
+    }
+    tc->last_tile = tile;
+    return tile;
+ }
index e075ab6290243e51fae8dcd41497383c16000ac8,c520aef44fa86d8ed17d9dd23db3676f51e98eda..608fbcc58966597b44fdb24190a2ba5348e2c326
@@@ -26,7 -26,7 +26,7 @@@
   **************************************************************************/
  
  /**
-  * Texture tile caching.
+  * Render target tile caching.
   *
   * Author:
   *    Brian Paul
@@@ -35,6 -35,8 +35,6 @@@
  #include "pipe/p_inlines.h"
  #include "util/u_memory.h"
  #include "util/u_tile.h"
 -#include "sp_context.h"
 -#include "sp_surface.h"
  #include "sp_tile_cache.h"
  
  
@@@ -108,10 -110,6 +108,6 @@@ sp_destroy_tile_cache(struct softpipe_t
        screen = tc->transfer->texture->screen;
        screen->tex_transfer_destroy(tc->transfer);
     }
-    if (tc->tex_trans) {
-       screen = tc->tex_trans->texture->screen;
-       screen->tex_transfer_destroy(tc->tex_trans);
-    }
  
     FREE( tc );
  }
@@@ -124,8 -122,6 +120,6 @@@ voi
  sp_tile_cache_set_surface(struct softpipe_tile_cache *tc,
                            struct pipe_surface *ps)
  {
-    assert(!tc->texture);
     if (tc->transfer) {
        struct pipe_screen *screen = tc->transfer->texture->screen;
  
@@@ -177,9 -173,6 +171,6 @@@ sp_tile_cache_map_transfers(struct soft
  {
     if (tc->transfer && !tc->transfer_map)
        tc->transfer_map = tc->screen->transfer_map(tc->screen, tc->transfer);
-    if (tc->tex_trans && !tc->tex_trans_map)
-       tc->tex_trans_map = tc->screen->transfer_map(tc->screen, tc->tex_trans);
  }
  
  
@@@ -190,69 -183,8 +181,9 @@@ sp_tile_cache_unmap_transfers(struct so
        tc->screen->transfer_unmap(tc->screen, tc->transfer);
        tc->transfer_map = NULL;
     }
-    if (tc->tex_trans_map) {
-       tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
-       tc->tex_trans_map = NULL;
-    }
- }
- /**
-  * Invalidate all cached tiles for the cached texture.
-  * Should be called when the texture is modified.
-  */
- void
- sp_tile_cache_validate_texture(struct softpipe_tile_cache *tc)
- {
-    uint i;
-    assert(tc);
-    assert(tc->texture);
-    for (i = 0; i < NUM_ENTRIES; i++) {
-       tc->entries[i].addr.bits.invalid = 1;
-    }
- }
- /**
-  * Specify the texture to cache.
-  */
- void
- sp_tile_cache_set_texture(struct softpipe_tile_cache *tc,
-                           struct pipe_texture *texture)
- {
-    uint i;
-    assert(!tc->transfer);
-    if (tc->texture != texture) {
-       pipe_texture_reference(&tc->texture, texture);
-       if (tc->tex_trans) {
-          struct pipe_screen *screen = tc->tex_trans->texture->screen;
-          
-          if (tc->tex_trans_map) {
-             screen->transfer_unmap(screen, tc->tex_trans);
-             tc->tex_trans_map = NULL;
-          }
-          screen->tex_transfer_destroy(tc->tex_trans);
-          tc->tex_trans = NULL;
-       }
-       /* mark as entries as invalid/empty */
-       /* XXX we should try to avoid this when the teximage hasn't changed */
-       for (i = 0; i < NUM_ENTRIES; i++) {
-          tc->entries[i].addr.bits.invalid = 1;
-       }
-       tc->tex_face = -1; /* any invalid value here */
-    }
  }
  
 +
  /**
   * Set pixels in a tile to the given clear color/value, float.
   */
@@@ -293,7 -225,7 +224,7 @@@ clear_tile(struct softpipe_cached_tile 
  
     switch (pf_get_size(format)) {
     case 1:
-       memset(tile->data.any, 0, TILE_SIZE * TILE_SIZE);
+       memset(tile->data.any, clear_value, TILE_SIZE * TILE_SIZE);
        break;
     case 2:
        if (clear_value == 0) {
@@@ -343,7 -275,7 +274,7 @@@ sp_tile_cache_flush_clear(struct softpi
     /* push the tile to all positions marked as clear */
     for (y = 0; y < h; y += TILE_SIZE) {
        for (x = 0; x < w; x += TILE_SIZE) {
-          union tile_address addr = tile_address(x, y, 0, 0, 0);
+          union tile_address addr = tile_address(x, y);
  
           if (is_clear_flag_set(tc->clear_flags, addr)) {
              pipe_put_tile_raw(pt,
@@@ -401,13 -333,6 +332,6 @@@ sp_flush_tile_cache(struct softpipe_til
        sp_tile_cache_flush_clear(tc);
  #endif
     }
-    else if (tc->texture) {
-       /* caching a texture, mark all entries as empty */
-       for (pos = 0; pos < NUM_ENTRIES; pos++) {
-          tc->entries[pos].addr.bits.invalid = 1;
-       }
-       tc->tex_face = -1;
-    }
  
  #if 0
     debug_printf("flushed tiles in use: %d\n", inuse);
@@@ -486,97 -411,7 +410,7 @@@ sp_find_cached_tile(struct softpipe_til
  }
  
  
- /**
-  * Given the texture face, level, zslice, x and y values, compute
-  * the cache entry position/index where we'd hope to find the
-  * cached texture tile.
-  * This is basically a direct-map cache.
-  * XXX There's probably lots of ways in which we can improve this.
-  */
- static INLINE uint
- tex_cache_pos( union tile_address addr )
- {
-    uint entry = (addr.bits.x + 
-                  addr.bits.y * 9 + 
-                  addr.bits.z * 3 + 
-                  addr.bits.face + 
-                  addr.bits.level * 7);
-    return entry % NUM_ENTRIES;
- }
  
- /**
-  * Similar to sp_get_cached_tile() but for textures.
-  * Tiles are read-only and indexed with more params.
-  */
- const struct softpipe_cached_tile *
- sp_find_cached_tile_tex(struct softpipe_tile_cache *tc, 
-                         union tile_address addr )
- {
-    struct pipe_screen *screen = tc->screen;
-    struct softpipe_cached_tile *tile;
-    
-    tile = tc->entries + tex_cache_pos( addr );
-    if (addr.value != tile->addr.value) {
-       /* cache miss.  Most misses are because we've invaldiated the
-        * texture cache previously -- most commonly on binding a new
-        * texture.  Currently we effectively flush the cache on texture
-        * bind.
-        */
- #if 0
-       _debug_printf("miss at %u:  x=%d y=%d z=%d face=%d level=%d\n"
-                     "   tile %u:  x=%d y=%d z=%d face=%d level=%d\n",
-                     pos, x/TILE_SIZE, y/TILE_SIZE, z, face, level,
-                     pos, tile->addr.bits.x, tile->addr.bits.y, tile->z, tile->face, tile->level);
- #endif
-       /* check if we need to get a new transfer */
-       if (!tc->tex_trans ||
-           tc->tex_face != addr.bits.face ||
-           tc->tex_level != addr.bits.level ||
-           tc->tex_z != addr.bits.z) {
-          /* get new transfer (view into texture) */
-          if (tc->tex_trans) {
-             if (tc->tex_trans_map) {
-                tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
-                tc->tex_trans_map = NULL;
-             }
-             screen->tex_transfer_destroy(tc->tex_trans);
-             tc->tex_trans = NULL;
-          }
-          tc->tex_trans = 
-             screen->get_tex_transfer(screen, tc->texture, 
-                                      addr.bits.face, 
-                                      addr.bits.level, 
-                                      addr.bits.z, 
-                                      PIPE_TRANSFER_READ, 0, 0,
-                                      tc->texture->width[addr.bits.level],
-                                      tc->texture->height[addr.bits.level]);
-          tc->tex_trans_map = screen->transfer_map(screen, tc->tex_trans);
-          tc->tex_face = addr.bits.face;
-          tc->tex_level = addr.bits.level;
-          tc->tex_z = addr.bits.z;
-       }
-       /* get tile from the transfer (view into texture) */
-       pipe_get_tile_rgba(tc->tex_trans,
-                          addr.bits.x * TILE_SIZE, 
-                          addr.bits.y * TILE_SIZE,
-                          TILE_SIZE, TILE_SIZE,
-                          (float *) tile->data.color);
-       tile->addr = addr;
-    }
-    tc->last_tile = tile;
-    return tile;
- }
  
  
  /**
index 1596cd0ae7622db0802d27ad73761fa0b7daf6ee,3b0be274d5e94dfd6f36e0a1429eccf0090cbca1..a80678e8658610a3bcd71c31c36c29d9e632db41
@@@ -34,6 -34,7 +34,6 @@@
  #include "pipe/p_compiler.h"
  
  
 -struct softpipe_context;
  struct softpipe_tile_cache;
  
  
@@@ -50,10 -51,8 +50,8 @@@ union tile_address 
     struct {
        unsigned x:6;             /* 4096 / TILE_SIZE */
        unsigned y:6;             /* 4096 / TILE_SIZE */
-       unsigned z:12;            /* 4096 -- z not tiled */
-       unsigned face:3;
-       unsigned level:4;
        unsigned invalid:1;
+       unsigned pad:19;
     } bits;
     unsigned value;
  };
@@@ -87,19 -86,12 +85,12 @@@ struct softpipe_tile_cach
     struct pipe_transfer *transfer;
     void *transfer_map;
  
-    struct pipe_texture *texture;  /**< if caching a texture */
-    unsigned timestamp;
     struct softpipe_cached_tile entries[NUM_ENTRIES];
     uint clear_flags[(MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32];
     float clear_color[4];  /**< for color bufs */
     uint clear_val;        /**< for z+stencil, or packed color clear value */
     boolean depth_stencil; /**< Is the surface a depth/stencil format? */
  
-    struct pipe_transfer *tex_trans;
-    void *tex_trans_map;
-    int tex_face, tex_level, tex_z;
     struct softpipe_cached_tile tile;  /**< scratch tile for clears */
  
     struct softpipe_cached_tile *last_tile;  /**< most recently retrieved tile */
@@@ -125,13 -117,6 +116,6 @@@ sp_tile_cache_map_transfers(struct soft
  extern void
  sp_tile_cache_unmap_transfers(struct softpipe_tile_cache *tc);
  
- extern void
- sp_tile_cache_set_texture(struct softpipe_tile_cache *tc,
-                           struct pipe_texture *texture);
- void
- sp_tile_cache_validate_texture(struct softpipe_tile_cache *tc);
  extern void
  sp_flush_tile_cache(struct softpipe_tile_cache *tc);
  
@@@ -143,47 -128,27 +127,27 @@@ extern struct softpipe_cached_tile 
  sp_find_cached_tile(struct softpipe_tile_cache *tc, 
                      union tile_address addr );
  
- extern const struct softpipe_cached_tile *
- sp_find_cached_tile_tex(struct softpipe_tile_cache *tc, 
-                          union tile_address addr );
  
  static INLINE const union tile_address
  tile_address( unsigned x,
-               unsigned y,
-               unsigned z,
-               unsigned face,
-               unsigned level )
+               unsigned y )
  {
     union tile_address addr;
  
     addr.value = 0;
     addr.bits.x = x / TILE_SIZE;
     addr.bits.y = y / TILE_SIZE;
-    addr.bits.z = z;
-    addr.bits.face = face;
-    addr.bits.level = level;
        
     return addr;
  }
  
  /* Quickly retrieve tile if it matches last lookup.
   */
- static INLINE const struct softpipe_cached_tile *
- sp_get_cached_tile_tex(struct softpipe_tile_cache *tc, 
-                          union tile_address addr )
- {
-    if (tc->last_tile->addr.value == addr.value)
-       return tc->last_tile;
-    return sp_find_cached_tile_tex( tc, addr );
- }
  static INLINE struct softpipe_cached_tile *
  sp_get_cached_tile(struct softpipe_tile_cache *tc, 
                     int x, int y )
  {
-    union tile_address addr = tile_address( x, y, 0, 0, 0 );
+    union tile_address addr = tile_address( x, y );
  
     if (tc->last_tile->addr.value == addr.value)
        return tc->last_tile;