softpipe: shortcircuit repeated lookups of the same tile
[mesa.git] / src / gallium / drivers / softpipe / sp_tex_sample.c
index 631c60966c2e423d744a883a870901e40850e186..46c56b0c835e67b135fc662bccb9e868e8c27ea6 100644 (file)
@@ -2,6 +2,7 @@
  * 
  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
  * All Rights Reserved.
+ * Copyright 2008 VMware, Inc.  All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the
  */
 
 #include "sp_context.h"
-#include "sp_headers.h"
+#include "sp_quad.h"
 #include "sp_surface.h"
 #include "sp_texture.h"
 #include "sp_tex_sample.h"
 #include "sp_tile_cache.h"
 #include "pipe/p_context.h"
 #include "pipe/p_defines.h"
-#include "tgsi/tgsi_exec.h"
 #include "util/u_math.h"
 #include "util/u_memory.h"
 
 
+
 /*
  * Note, the FRAC macro has to work perfectly.  Otherwise you'll sometimes
  * see 1-pixel bands of improperly weighted linear-filtered textures.
@@ -583,6 +584,7 @@ choose_mipmap_levels(const struct pipe_texture *texture,
                      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)
@@ -611,7 +613,7 @@ choose_mipmap_levels(const struct pipe_texture *texture,
    else {
       float lambda;
 
-      if (1)
+      if (computeLambda)
          /* fragment shader */
          lambda = compute_lambda(texture, sampler, s, t, p, lodbias);
       else
@@ -666,10 +668,8 @@ get_texel(const struct tgsi_sampler *tgsi_sampler,
           float rgba[NUM_CHANNELS][QUAD_SIZE], unsigned j)
 {
    const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
-   struct softpipe_context *sp = samp->sp;
-   const uint unit = samp->unit;
-   const struct pipe_texture *texture = sp->texture[unit];
-   const struct pipe_sampler_state *sampler = sp->sampler[unit];
+   const struct pipe_texture *texture = samp->texture;
+   const struct pipe_sampler_state *sampler = samp->sampler;
 
    if (x < 0 || x >= (int) texture->width[level] ||
        y < 0 || y >= (int) texture->height[level] ||
@@ -680,11 +680,13 @@ get_texel(const struct tgsi_sampler *tgsi_sampler,
       rgba[3][j] = sampler->border_color[3];
    }
    else {
-      const int tx = x % TILE_SIZE;
-      const int ty = y % TILE_SIZE;
-      const struct softpipe_cached_tile *tile
-         = sp_get_cached_tile_tex(sp, samp->cache,
-                                  x, y, z, face, level);
+      const unsigned tx = x % TILE_SIZE;
+      const unsigned ty = y % TILE_SIZE;
+      const struct softpipe_cached_tile *tile;
+
+      tile = sp_get_cached_tile_tex(samp->cache, 
+                                    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];
       rgba[2][j] = tile->data.color[ty][tx][2];
@@ -703,15 +705,18 @@ get_texel(const struct tgsi_sampler *tgsi_sampler,
  * 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(uint compare_func,
+shadow_compare(const struct pipe_sampler_state *sampler,
                float rgba[NUM_CHANNELS][QUAD_SIZE],
                const float p[QUAD_SIZE],
                uint j)
 {
    int k;
-   switch (compare_func) {
+   switch (sampler->compare_func) {
    case PIPE_FUNC_LESS:
       k = p[j] < rgba[0][j];
       break;
@@ -742,7 +747,81 @@ shadow_compare(uint compare_func,
       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;
+   }
 }
 
 
@@ -755,21 +834,19 @@ 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])
 {
    const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
-   const struct softpipe_context *sp = samp->sp;
-   const uint unit = samp->unit;
-   const struct pipe_texture *texture = sp->texture[unit];
-   const struct pipe_sampler_state *sampler = sp->sampler[unit];
-   const uint compare_func = sampler->compare_func;
+   const struct pipe_texture *texture = samp->texture;
+   const struct pipe_sampler_state *sampler = samp->sampler;
    unsigned level0, level1, j, imgFilter;
    int width, height;
    float levelBlend;
 
-   choose_mipmap_levels(texture, sampler, s, t, p, lodbias,
+   choose_mipmap_levels(texture, sampler, s, t, p, computeLambda, lodbias,
                         &level0, &level1, &levelBlend, &imgFilter);
 
    assert(sampler->normalized_coords);
@@ -789,7 +866,7 @@ sp_get_samples_2d_common(const struct tgsi_sampler *tgsi_sampler,
          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(compare_func, rgba, p, j);
+               shadow_compare(sampler, rgba, p, j);
             }
 
             if (level0 != level1) {
@@ -801,7 +878,7 @@ sp_get_samples_2d_common(const struct tgsi_sampler *tgsi_sampler,
                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(compare_func, rgba2, p, j);
+                  shadow_compare(sampler, rgba2, p, j);
                }
 
                for (c = 0; c < NUM_CHANNELS; c++) {
@@ -828,10 +905,7 @@ sp_get_samples_2d_common(const struct tgsi_sampler *tgsi_sampler,
             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_compare(compare_func, tx, p, 0);
-               shadow_compare(compare_func, tx, p, 1);
-               shadow_compare(compare_func, tx, p, 2);
-               shadow_compare(compare_func, tx, p, 3);
+               shadow_compare4(sampler, tx, p);
             }
 
             /* interpolate R, G, B, A */
@@ -853,10 +927,7 @@ sp_get_samples_2d_common(const struct tgsi_sampler *tgsi_sampler,
                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_compare(compare_func, tx, p, 0);
-                  shadow_compare(compare_func, tx, p, 1);
-                  shadow_compare(compare_func, tx, p, 2);
-                  shadow_compare(compare_func, tx, p, 3);
+                  shadow_compare4(sampler, tx, p);
                }
 
                /* interpolate R, G, B, A */
@@ -883,12 +954,14 @@ 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, lodbias, rgba, faces);
+   sp_get_samples_2d_common(sampler, s, tzero, NULL,
+                            computeLambda, lodbias, rgba, faces);
 }
 
 
@@ -897,11 +970,13 @@ 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, lodbias, rgba, faces);
+   sp_get_samples_2d_common(sampler, s, t, p,
+                            computeLambda, lodbias, rgba, faces);
 }
 
 
@@ -910,21 +985,20 @@ 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])
 {
    const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
-   const struct softpipe_context *sp = samp->sp;
-   const uint unit = samp->unit;
-   const struct pipe_texture *texture = sp->texture[unit];
-   const struct pipe_sampler_state *sampler = sp->sampler[unit];
+   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;
    int width, height, depth;
    float levelBlend;
    const uint face = 0;
 
-   choose_mipmap_levels(texture, sampler, s, t, p, lodbias,
+   choose_mipmap_levels(texture, sampler, s, t, p, computeLambda, lodbias,
                         &level0, &level1, &levelBlend, &imgFilter);
 
    assert(sampler->normalized_coords);
@@ -1037,6 +1111,7 @@ 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])
 {
@@ -1045,7 +1120,8 @@ sp_get_samples_cube(const struct tgsi_sampler *sampler,
    for (j = 0; j < QUAD_SIZE; j++) {
       faces[j] = choose_cube_face(s[j], t[j], p[j], ssss + j, tttt + j);
    }
-   sp_get_samples_2d_common(sampler, ssss, tttt, NULL, lodbias, rgba, faces);
+   sp_get_samples_2d_common(sampler, ssss, tttt, NULL,
+                            computeLambda, lodbias, rgba, faces);
 }
 
 
@@ -1054,21 +1130,19 @@ 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])
 {
    const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
-   const struct softpipe_context *sp = samp->sp;
-   const uint unit = samp->unit;
-   const struct pipe_texture *texture = sp->texture[unit];
-   const struct pipe_sampler_state *sampler = sp->sampler[unit];
+   const struct pipe_texture *texture = samp->texture;
+   const struct pipe_sampler_state *sampler = samp->sampler;
    const uint face = 0;
-   const uint compare_func = sampler->compare_func;
    unsigned level0, level1, j, imgFilter;
    int width, height;
    float levelBlend;
 
-   choose_mipmap_levels(texture, sampler, s, t, p, lodbias,
+   choose_mipmap_levels(texture, sampler, s, t, p, computeLambda, lodbias,
                         &level0, &level1, &levelBlend, &imgFilter);
 
    /* texture RECTS cannot be mipmapped */
@@ -1088,7 +1162,7 @@ sp_get_samples_rect(const struct tgsi_sampler *tgsi_sampler,
          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(compare_func, rgba, p, j);
+               shadow_compare(sampler, rgba, p, j);
             }
          }
       }
@@ -1108,10 +1182,7 @@ sp_get_samples_rect(const struct tgsi_sampler *tgsi_sampler,
             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_compare(compare_func, tx, p, 0);
-               shadow_compare(compare_func, tx, p, 1);
-               shadow_compare(compare_func, tx, p, 2);
-               shadow_compare(compare_func, tx, p, 3);
+               shadow_compare4(sampler, tx, p);
             }
             for (c = 0; c < 4; c++) {
                rgba[c][j] = lerp_2d(xw[j], yw[j],
@@ -1127,22 +1198,20 @@ sp_get_samples_rect(const struct tgsi_sampler *tgsi_sampler,
 
 
 /**
- * Called via tgsi_sampler::get_samples()
- * Get four filtered RGBA values from the sampler's texture.
+ * Common code for vertex/fragment program texture sampling.
  */
-void
+static INLINE void
 sp_get_samples(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 softpipe_context *sp = samp->sp;
-   const uint unit = samp->unit;
-   const struct pipe_texture *texture = sp->texture[unit];
-   const struct pipe_sampler_state *sampler = sp->sampler[unit];
+   const struct pipe_texture *texture = samp->texture;
+   const struct pipe_sampler_state *sampler = samp->sampler;
 
    if (!texture)
       return;
@@ -1150,21 +1219,21 @@ sp_get_samples(struct tgsi_sampler *tgsi_sampler,
    switch (texture->target) {
    case PIPE_TEXTURE_1D:
       assert(sampler->normalized_coords);
-      sp_get_samples_1d(tgsi_sampler, s, t, p, lodbias, rgba);
+      sp_get_samples_1d(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba);
       break;
    case PIPE_TEXTURE_2D:
       if (sampler->normalized_coords)
-         sp_get_samples_2d(tgsi_sampler, s, t, p, lodbias, rgba);
+         sp_get_samples_2d(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba);
       else
-         sp_get_samples_rect(tgsi_sampler, s, t, p, lodbias, rgba);
+         sp_get_samples_rect(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba);
       break;
    case PIPE_TEXTURE_3D:
       assert(sampler->normalized_coords);
-      sp_get_samples_3d(tgsi_sampler, s, t, p, lodbias, rgba);
+      sp_get_samples_3d(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba);
       break;
    case PIPE_TEXTURE_CUBE:
       assert(sampler->normalized_coords);
-      sp_get_samples_cube(tgsi_sampler, s, t, p, lodbias, rgba);
+      sp_get_samples_cube(tgsi_sampler, s, t, p, computeLambda, lodbias, rgba);
       break;
    default:
       assert(0);
@@ -1185,3 +1254,34 @@ sp_get_samples(struct tgsi_sampler *tgsi_sampler,
 #endif
 }
 
+
+/**
+ * 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])
+{
+   sp_get_samples(tgsi_sampler, s, t, p, TRUE, lodbias, rgba);
+}
+
+
+/**
+ * Called via tgsi_sampler::get_samples() when running a vertex shader.
+ * Get four filtered RGBA values from the sampler's texture.
+ */
+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(tgsi_sampler, s, t, p, FALSE, lodbias, rgba);
+}