sp_tex_sample.c

Go to the documentation of this file.
00001 /**************************************************************************
00002  * 
00003  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
00004  * All Rights Reserved.
00005  *
00006  * Permission is hereby granted, free of charge, to any person obtaining a
00007  * copy of this software and associated documentation files (the
00008  * "Software"), to deal in the Software without restriction, including
00009  * without limitation the rights to use, copy, modify, merge, publish,
00010  * distribute, sub license, and/or sell copies of the Software, and to
00011  * permit persons to whom the Software is furnished to do so, subject to
00012  * the following conditions:
00013  * 
00014  * The above copyright notice and this permission notice (including the
00015  * next paragraph) shall be included in all copies or substantial portions
00016  * of the Software.
00017  * 
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00019  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
00021  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
00022  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
00023  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
00024  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00025  * 
00026  **************************************************************************/
00027 
00035 #include "sp_context.h"
00036 #include "sp_headers.h"
00037 #include "sp_surface.h"
00038 #include "sp_tex_sample.h"
00039 #include "sp_tile_cache.h"
00040 #include "pipe/p_context.h"
00041 #include "pipe/p_defines.h"
00042 #include "tgsi/tgsi_exec.h"
00043 #include "util/u_math.h"
00044 #include "util/u_memory.h"
00045 
00046 
00047 /*
00048  * Note, the FRAC macro has to work perfectly.  Otherwise you'll sometimes
00049  * see 1-pixel bands of improperly weighted linear-filtered textures.
00050  * The tests/texwrap.c demo is a good test.
00051  * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
00052  * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
00053  */
00054 #define FRAC(f)  ((f) - util_ifloor(f))
00055 
00056 
00060 #define LERP(T, A, B)  ( (A) + (T) * ((B) - (A)) )
00061 
00062 
00071 static INLINE float
00072 lerp_2d(float a, float b,
00073         float v00, float v10, float v01, float v11)
00074 {
00075    const float temp0 = LERP(a, v00, v10);
00076    const float temp1 = LERP(a, v01, v11);
00077    return LERP(b, temp0, temp1);
00078 }
00079 
00080 
00085 #define REMAINDER(A, B) ((unsigned) (A) % (unsigned) (B))
00086 
00087 
00095 static INLINE int
00096 nearest_texcoord(unsigned wrapMode, float s, unsigned size)
00097 {
00098    int i;
00099    switch (wrapMode) {
00100    case PIPE_TEX_WRAP_REPEAT:
00101       /* s limited to [0,1) */
00102       /* i limited to [0,size-1] */
00103       i = util_ifloor(s * size);
00104       i = REMAINDER(i, size);
00105       return i;
00106    case PIPE_TEX_WRAP_CLAMP:
00107       /* s limited to [0,1] */
00108       /* i limited to [0,size-1] */
00109       if (s <= 0.0F)
00110          i = 0;
00111       else if (s >= 1.0F)
00112          i = size - 1;
00113       else
00114          i = util_ifloor(s * size);
00115       return i;
00116    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
00117       {
00118          /* s limited to [min,max] */
00119          /* i limited to [0, size-1] */
00120          const float min = 1.0F / (2.0F * size);
00121          const float max = 1.0F - min;
00122          if (s < min)
00123             i = 0;
00124          else if (s > max)
00125             i = size - 1;
00126          else
00127             i = util_ifloor(s * size);
00128       }
00129       return i;
00130    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
00131       {
00132          /* s limited to [min,max] */
00133          /* i limited to [-1, size] */
00134          const float min = -1.0F / (2.0F * size);
00135          const float max = 1.0F - min;
00136          if (s <= min)
00137             i = -1;
00138          else if (s >= max)
00139             i = size;
00140          else
00141             i = util_ifloor(s * size);
00142       }
00143       return i;
00144    case PIPE_TEX_WRAP_MIRROR_REPEAT:
00145       {
00146          const float min = 1.0F / (2.0F * size);
00147          const float max = 1.0F - min;
00148          const int flr = util_ifloor(s);
00149          float u;
00150          if (flr & 1)
00151             u = 1.0F - (s - (float) flr);
00152          else
00153             u = s - (float) flr;
00154          if (u < min)
00155             i = 0;
00156          else if (u > max)
00157             i = size - 1;
00158          else
00159             i = util_ifloor(u * size);
00160       }
00161       return i;
00162    case PIPE_TEX_WRAP_MIRROR_CLAMP:
00163       {
00164          /* s limited to [0,1] */
00165          /* i limited to [0,size-1] */
00166          const float u = fabsf(s);
00167          if (u <= 0.0F)
00168             i = 0;
00169          else if (u >= 1.0F)
00170             i = size - 1;
00171          else
00172             i = util_ifloor(u * size);
00173       }
00174       return i;
00175    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
00176       {
00177          /* s limited to [min,max] */
00178          /* i limited to [0, size-1] */
00179          const float min = 1.0F / (2.0F * size);
00180          const float max = 1.0F - min;
00181          const float u = fabsf(s);
00182          if (u < min)
00183             i = 0;
00184          else if (u > max)
00185             i = size - 1;
00186          else
00187             i = util_ifloor(u * size);
00188       }
00189       return i;
00190    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
00191       {
00192          /* s limited to [min,max] */
00193          /* i limited to [0, size-1] */
00194          const float min = -1.0F / (2.0F * size);
00195          const float max = 1.0F - min;
00196          const float u = fabsf(s);
00197          if (u < min)
00198             i = -1;
00199          else if (u > max)
00200             i = size;
00201          else
00202             i = util_ifloor(u * size);
00203       }
00204       return i;
00205    default:
00206       assert(0);
00207       return 0;
00208    }
00209 }
00210 
00211 
00221 static INLINE void
00222 linear_texcoord(unsigned wrapMode, float s, unsigned size,
00223                 int *i0, int *i1, float *a)
00224 {
00225    float u;
00226    switch (wrapMode) {
00227    case PIPE_TEX_WRAP_REPEAT:
00228       u = s * size - 0.5F;
00229       *i0 = REMAINDER(util_ifloor(u), size);
00230       *i1 = REMAINDER(*i0 + 1, size);
00231       break;
00232    case PIPE_TEX_WRAP_CLAMP:
00233       if (s <= 0.0F)
00234          u = 0.0F;
00235       else if (s >= 1.0F)
00236          u = (float) size;
00237       else
00238          u = s * size;
00239       u -= 0.5F;
00240       *i0 = util_ifloor(u);
00241       *i1 = *i0 + 1;
00242       break;
00243    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
00244       if (s <= 0.0F)
00245          u = 0.0F;
00246       else if (s >= 1.0F)
00247          u = (float) size;
00248       else
00249          u = s * size;
00250       u -= 0.5F;
00251       *i0 = util_ifloor(u);
00252       *i1 = *i0 + 1;
00253       if (*i0 < 0)
00254          *i0 = 0;
00255       if (*i1 >= (int) size)
00256          *i1 = size - 1;
00257       break;
00258    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
00259       {
00260          const float min = -1.0F / (2.0F * size);
00261          const float max = 1.0F - min;
00262          if (s <= min)
00263             u = min * size;
00264          else if (s >= max)
00265             u = max * size;
00266          else
00267             u = s * size;
00268          u -= 0.5F;
00269          *i0 = util_ifloor(u);
00270          *i1 = *i0 + 1;
00271       }
00272       break;
00273    case PIPE_TEX_WRAP_MIRROR_REPEAT:
00274       {
00275          const int flr = util_ifloor(s);
00276          if (flr & 1)
00277             u = 1.0F - (s - (float) flr);
00278          else
00279             u = s - (float) flr;
00280          u = (u * size) - 0.5F;
00281          *i0 = util_ifloor(u);
00282          *i1 = *i0 + 1;
00283          if (*i0 < 0)
00284             *i0 = 0;
00285          if (*i1 >= (int) size)
00286             *i1 = size - 1;
00287       }
00288       break;
00289    case PIPE_TEX_WRAP_MIRROR_CLAMP:
00290       u = fabsf(s);
00291       if (u >= 1.0F)
00292          u = (float) size;
00293       else
00294          u *= size;
00295       u -= 0.5F;
00296       *i0 = util_ifloor(u);
00297       *i1 = *i0 + 1;
00298       break;
00299    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
00300       u = fabsf(s);
00301       if (u >= 1.0F)
00302          u = (float) size;
00303       else
00304          u *= size;
00305       u -= 0.5F;
00306       *i0 = util_ifloor(u);
00307       *i1 = *i0 + 1;
00308       if (*i0 < 0)
00309          *i0 = 0;
00310       if (*i1 >= (int) size)
00311          *i1 = size - 1;
00312       break;
00313    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
00314       {
00315          const float min = -1.0F / (2.0F * size);
00316          const float max = 1.0F - min;
00317          u = fabsf(s);
00318          if (u <= min)
00319             u = min * size;
00320          else if (u >= max)
00321             u = max * size;
00322          else
00323             u *= size;
00324          u -= 0.5F;
00325          *i0 = util_ifloor(u);
00326          *i1 = *i0 + 1;
00327       }
00328       break;
00329    default:
00330       assert(0);
00331    }
00332    *a = FRAC(u);
00333 }
00334 
00335 
00340 static INLINE int
00341 nearest_texcoord_unnorm(unsigned wrapMode, float s, unsigned size)
00342 {
00343    int i;
00344    switch (wrapMode) {
00345    case PIPE_TEX_WRAP_CLAMP:
00346       i = util_ifloor(s);
00347       return CLAMP(i, 0, (int) size-1);
00348    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
00349       /* fall-through */
00350    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
00351       return util_ifloor( CLAMP(s, 0.5F, (float) size - 0.5F) );
00352    default:
00353       assert(0);
00354       return 0;
00355    }
00356 }
00357 
00358 
00363 static INLINE void
00364 linear_texcoord_unnorm(unsigned wrapMode, float s, unsigned size,
00365                        int *i0, int *i1, float *a)
00366 {
00367    switch (wrapMode) {
00368    case PIPE_TEX_WRAP_CLAMP:
00369       /* Not exactly what the spec says, but it matches NVIDIA output */
00370       s = CLAMP(s - 0.5F, 0.0f, (float) size - 1.0f);
00371       *i0 = util_ifloor(s);
00372       *i1 = *i0 + 1;
00373       break;
00374    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
00375       /* fall-through */
00376    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
00377       s = CLAMP(s, 0.5F, (float) size - 0.5F);
00378       s -= 0.5F;
00379       *i0 = util_ifloor(s);
00380       *i1 = *i0 + 1;
00381       if (*i1 > (int) size - 1)
00382          *i1 = size - 1;
00383       break;
00384    default:
00385       assert(0);
00386    }
00387    *a = FRAC(s);
00388 }
00389 
00390 
00391 static unsigned
00392 choose_cube_face(float rx, float ry, float rz, float *newS, float *newT)
00393 {
00394    /*
00395       major axis
00396       direction     target                             sc     tc    ma
00397       ----------    -------------------------------    ---    ---   ---
00398        +rx          TEXTURE_CUBE_MAP_POSITIVE_X_EXT    -rz    -ry   rx
00399        -rx          TEXTURE_CUBE_MAP_NEGATIVE_X_EXT    +rz    -ry   rx
00400        +ry          TEXTURE_CUBE_MAP_POSITIVE_Y_EXT    +rx    +rz   ry
00401        -ry          TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT    +rx    -rz   ry
00402        +rz          TEXTURE_CUBE_MAP_POSITIVE_Z_EXT    +rx    -ry   rz
00403        -rz          TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT    -rx    -ry   rz
00404    */
00405    const float arx = fabsf(rx), ary = fabsf(ry), arz = fabsf(rz);
00406    unsigned face;
00407    float sc, tc, ma;
00408 
00409    if (arx > ary && arx > arz) {
00410       if (rx >= 0.0F) {
00411          face = PIPE_TEX_FACE_POS_X;
00412          sc = -rz;
00413          tc = -ry;
00414          ma = arx;
00415       }
00416       else {
00417          face = PIPE_TEX_FACE_NEG_X;
00418          sc = rz;
00419          tc = -ry;
00420          ma = arx;
00421       }
00422    }
00423    else if (ary > arx && ary > arz) {
00424       if (ry >= 0.0F) {
00425          face = PIPE_TEX_FACE_POS_Y;
00426          sc = rx;
00427          tc = rz;
00428          ma = ary;
00429       }
00430       else {
00431          face = PIPE_TEX_FACE_NEG_Y;
00432          sc = rx;
00433          tc = -rz;
00434          ma = ary;
00435       }
00436    }
00437    else {
00438       if (rz > 0.0F) {
00439          face = PIPE_TEX_FACE_POS_Z;
00440          sc = rx;
00441          tc = -ry;
00442          ma = arz;
00443       }
00444       else {
00445          face = PIPE_TEX_FACE_NEG_Z;
00446          sc = -rx;
00447          tc = -ry;
00448          ma = arz;
00449       }
00450    }
00451 
00452    *newS = ( sc / ma + 1.0F ) * 0.5F;
00453    *newT = ( tc / ma + 1.0F ) * 0.5F;
00454 
00455    return face;
00456 }
00457 
00458 
00465 static float
00466 compute_lambda(struct tgsi_sampler *sampler,
00467                const float s[QUAD_SIZE],
00468                const float t[QUAD_SIZE],
00469                const float p[QUAD_SIZE],
00470                float lodbias)
00471 {
00472    float rho, lambda;
00473 
00474    assert(sampler->state->normalized_coords);
00475 
00476    assert(s);
00477    {
00478       float dsdx = s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT];
00479       float dsdy = s[QUAD_TOP_LEFT]     - s[QUAD_BOTTOM_LEFT];
00480       dsdx = fabsf(dsdx);
00481       dsdy = fabsf(dsdy);
00482       rho = MAX2(dsdx, dsdy) * sampler->texture->width[0];
00483    }
00484    if (t) {
00485       float dtdx = t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT];
00486       float dtdy = t[QUAD_TOP_LEFT]     - t[QUAD_BOTTOM_LEFT];
00487       float max;
00488       dtdx = fabsf(dtdx);
00489       dtdy = fabsf(dtdy);
00490       max = MAX2(dtdx, dtdy) * sampler->texture->height[0];
00491       rho = MAX2(rho, max);
00492    }
00493    if (p) {
00494       float dpdx = p[QUAD_BOTTOM_RIGHT] - p[QUAD_BOTTOM_LEFT];
00495       float dpdy = p[QUAD_TOP_LEFT]     - p[QUAD_BOTTOM_LEFT];
00496       float max;
00497       dpdx = fabsf(dpdx);
00498       dpdy = fabsf(dpdy);
00499       max = MAX2(dpdx, dpdy) * sampler->texture->depth[0];
00500       rho = MAX2(rho, max);
00501    }
00502 
00503    lambda = util_fast_log2(rho);
00504    lambda += lodbias + sampler->state->lod_bias;
00505    lambda = CLAMP(lambda, sampler->state->min_lod, sampler->state->max_lod);
00506 
00507    return lambda;
00508 }
00509 
00510 
00518 static void
00519 choose_mipmap_levels(struct tgsi_sampler *sampler,
00520                      const float s[QUAD_SIZE],
00521                      const float t[QUAD_SIZE],
00522                      const float p[QUAD_SIZE],
00523                      float lodbias,
00524                      unsigned *level0, unsigned *level1, float *levelBlend,
00525                      unsigned *imgFilter)
00526 {
00527    if (sampler->state->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) {
00528       /* no mipmap selection needed */
00529       *level0 = *level1 = CLAMP((int) sampler->state->min_lod,
00530                                 0, (int) sampler->texture->last_level);
00531 
00532       if (sampler->state->min_img_filter != sampler->state->mag_img_filter) {
00533          /* non-mipmapped texture, but still need to determine if doing
00534           * minification or magnification.
00535           */
00536          float lambda = compute_lambda(sampler, s, t, p, lodbias);
00537          if (lambda <= 0.0) {
00538             *imgFilter = sampler->state->mag_img_filter;
00539          }
00540          else {
00541             *imgFilter = sampler->state->min_img_filter;
00542          }
00543       }
00544       else {
00545          *imgFilter = sampler->state->mag_img_filter;
00546       }
00547    }
00548    else {
00549       float lambda;
00550 
00551       if (1)
00552          /* fragment shader */
00553          lambda = compute_lambda(sampler, s, t, p, lodbias);
00554       else
00555          /* vertex shader */
00556          lambda = lodbias; /* not really a bias, but absolute LOD */
00557 
00558       if (lambda <= 0.0) { /* XXX threshold depends on the filter */
00559          /* magnifying */
00560          *imgFilter = sampler->state->mag_img_filter;
00561          *level0 = *level1 = 0;
00562       }
00563       else {
00564          /* minifying */
00565          *imgFilter = sampler->state->min_img_filter;
00566 
00567          /* choose mipmap level(s) and compute the blend factor between them */
00568          if (sampler->state->min_mip_filter == PIPE_TEX_MIPFILTER_NEAREST) {
00569             /* Nearest mipmap level */
00570             const int lvl = (int) (lambda + 0.5);
00571             *level0 =
00572             *level1 = CLAMP(lvl, 0, (int) sampler->texture->last_level);
00573          }
00574          else {
00575             /* Linear interpolation between mipmap levels */
00576             const int lvl = (int) lambda;
00577             *level0 = CLAMP(lvl,     0, (int) sampler->texture->last_level);
00578             *level1 = CLAMP(lvl + 1, 0, (int) sampler->texture->last_level);
00579             *levelBlend = FRAC(lambda);  /* blending weight between levels */
00580          }
00581       }
00582    }
00583 }
00584 
00585 
00600 static void
00601 get_texel(struct tgsi_sampler *sampler,
00602           unsigned face, unsigned level, int x, int y, int z,
00603           float rgba[NUM_CHANNELS][QUAD_SIZE], unsigned j)
00604 {
00605    if (x < 0 || x >= (int) sampler->texture->width[level] ||
00606        y < 0 || y >= (int) sampler->texture->height[level] ||
00607        z < 0 || z >= (int) sampler->texture->depth[level]) {
00608       rgba[0][j] = sampler->state->border_color[0];
00609       rgba[1][j] = sampler->state->border_color[1];
00610       rgba[2][j] = sampler->state->border_color[2];
00611       rgba[3][j] = sampler->state->border_color[3];
00612    }
00613    else {
00614       const int tx = x % TILE_SIZE;
00615       const int ty = y % TILE_SIZE;
00616       const struct softpipe_cached_tile *tile
00617          = sp_get_cached_tile_tex(sampler->pipe, sampler->cache,
00618                                   x, y, z, face, level);
00619       rgba[0][j] = tile->data.color[ty][tx][0];
00620       rgba[1][j] = tile->data.color[ty][tx][1];
00621       rgba[2][j] = tile->data.color[ty][tx][2];
00622       rgba[3][j] = tile->data.color[ty][tx][3];
00623       if (0)
00624       {
00625          debug_printf("Get texel %f %f %f %f from %s\n",
00626                       rgba[0][j], rgba[1][j], rgba[2][j], rgba[3][j],
00627                       pf_name(sampler->texture->format));
00628       }
00629    }
00630 }
00631 
00632 
00638 static INLINE void
00639 shadow_compare(uint compare_func,
00640                float rgba[NUM_CHANNELS][QUAD_SIZE],
00641                const float p[QUAD_SIZE],
00642                uint j)
00643 {
00644    int k;
00645    switch (compare_func) {
00646    case PIPE_FUNC_LESS:
00647       k = p[j] < rgba[0][j];
00648       break;
00649    case PIPE_FUNC_LEQUAL:
00650       k = p[j] <= rgba[0][j];
00651       break;
00652    case PIPE_FUNC_GREATER:
00653       k = p[j] > rgba[0][j];
00654       break;
00655    case PIPE_FUNC_GEQUAL:
00656       k = p[j] >= rgba[0][j];
00657       break;
00658    case PIPE_FUNC_EQUAL:
00659       k = p[j] == rgba[0][j];
00660       break;
00661    case PIPE_FUNC_NOTEQUAL:
00662       k = p[j] != rgba[0][j];
00663       break;
00664    case PIPE_FUNC_ALWAYS:
00665       k = 1;
00666       break;
00667    case PIPE_FUNC_NEVER:
00668       k = 0;
00669       break;
00670    default:
00671       k = 0;
00672       assert(0);
00673       break;
00674    }
00675 
00676    rgba[0][j] = rgba[1][j] = rgba[2][j] = (float) k;
00677 }
00678 
00679 
00684 static void
00685 sp_get_samples_2d_common(struct tgsi_sampler *sampler,
00686                          const float s[QUAD_SIZE],
00687                          const float t[QUAD_SIZE],
00688                          const float p[QUAD_SIZE],
00689                          float lodbias,
00690                          float rgba[NUM_CHANNELS][QUAD_SIZE],
00691                          const unsigned faces[4])
00692 {
00693    const uint compare_func = sampler->state->compare_func;
00694    unsigned level0, level1, j, imgFilter;
00695    int width, height;
00696    float levelBlend;
00697 
00698    choose_mipmap_levels(sampler, s, t, p, lodbias,
00699                         &level0, &level1, &levelBlend, &imgFilter);
00700 
00701    assert(sampler->state->normalized_coords);
00702 
00703    width = sampler->texture->width[level0];
00704    height = sampler->texture->height[level0];
00705 
00706    assert(width > 0);
00707 
00708    switch (imgFilter) {
00709    case PIPE_TEX_FILTER_NEAREST:
00710       for (j = 0; j < QUAD_SIZE; j++) {
00711          int x = nearest_texcoord(sampler->state->wrap_s, s[j], width);
00712          int y = nearest_texcoord(sampler->state->wrap_t, t[j], height);
00713          get_texel(sampler, faces[j], level0, x, y, 0, rgba, j);
00714          if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
00715             shadow_compare(compare_func, rgba, p, j);
00716          }
00717 
00718          if (level0 != level1) {
00719             /* get texels from second mipmap level and blend */
00720             float rgba2[4][4];
00721             unsigned c;
00722             x = x / 2;
00723             y = y / 2;
00724             get_texel(sampler, faces[j], level1, x, y, 0, rgba2, j);
00725             if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
00726                shadow_compare(compare_func, rgba2, p, j);
00727             }
00728 
00729             for (c = 0; c < NUM_CHANNELS; c++) {
00730                rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
00731             }
00732          }
00733       }
00734       break;
00735    case PIPE_TEX_FILTER_LINEAR:
00736    case PIPE_TEX_FILTER_ANISO:
00737       for (j = 0; j < QUAD_SIZE; j++) {
00738          float tx[4][4], a, b;
00739          int x0, y0, x1, y1, c;
00740          linear_texcoord(sampler->state->wrap_s, s[j], width,  &x0, &x1, &a);
00741          linear_texcoord(sampler->state->wrap_t, t[j], height, &y0, &y1, &b);
00742          get_texel(sampler, faces[j], level0, x0, y0, 0, tx, 0);
00743          get_texel(sampler, faces[j], level0, x1, y0, 0, tx, 1);
00744          get_texel(sampler, faces[j], level0, x0, y1, 0, tx, 2);
00745          get_texel(sampler, faces[j], level0, x1, y1, 0, tx, 3);
00746          if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
00747             shadow_compare(compare_func, tx, p, 0);
00748             shadow_compare(compare_func, tx, p, 1);
00749             shadow_compare(compare_func, tx, p, 2);
00750             shadow_compare(compare_func, tx, p, 3);
00751          }
00752 
00753          for (c = 0; c < 4; c++) {
00754             rgba[c][j] = lerp_2d(a, b, tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
00755          }
00756 
00757          if (level0 != level1) {
00758             /* get texels from second mipmap level and blend */
00759             float rgba2[4][4];
00760             x0 = x0 / 2;
00761             y0 = y0 / 2;
00762             x1 = x1 / 2;
00763             y1 = y1 / 2;
00764             get_texel(sampler, faces[j], level1, x0, y0, 0, tx, 0);
00765             get_texel(sampler, faces[j], level1, x1, y0, 0, tx, 1);
00766             get_texel(sampler, faces[j], level1, x0, y1, 0, tx, 2);
00767             get_texel(sampler, faces[j], level1, x1, y1, 0, tx, 3);
00768             if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
00769                shadow_compare(compare_func, tx, p, 0);
00770                shadow_compare(compare_func, tx, p, 1);
00771                shadow_compare(compare_func, tx, p, 2);
00772                shadow_compare(compare_func, tx, p, 3);
00773             }
00774 
00775             for (c = 0; c < 4; c++) {
00776                rgba2[c][j] = lerp_2d(a, b,
00777                                      tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
00778             }
00779 
00780             for (c = 0; c < NUM_CHANNELS; c++) {
00781                rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
00782             }
00783          }
00784       }
00785       break;
00786    default:
00787       assert(0);
00788    }
00789 }
00790 
00791 
00792 static void
00793 sp_get_samples_1d(struct tgsi_sampler *sampler,
00794                   const float s[QUAD_SIZE],
00795                   const float t[QUAD_SIZE],
00796                   const float p[QUAD_SIZE],
00797                   float lodbias,
00798                   float rgba[NUM_CHANNELS][QUAD_SIZE])
00799 {
00800    static const unsigned faces[4] = {0, 0, 0, 0};
00801    static const float tzero[4] = {0, 0, 0, 0};
00802    sp_get_samples_2d_common(sampler, s, tzero, NULL, lodbias, rgba, faces);
00803 }
00804 
00805 
00806 static void
00807 sp_get_samples_2d(struct tgsi_sampler *sampler,
00808                   const float s[QUAD_SIZE],
00809                   const float t[QUAD_SIZE],
00810                   const float p[QUAD_SIZE],
00811                   float lodbias,
00812                   float rgba[NUM_CHANNELS][QUAD_SIZE])
00813 {
00814    static const unsigned faces[4] = {0, 0, 0, 0};
00815    sp_get_samples_2d_common(sampler, s, t, p, lodbias, rgba, faces);
00816 }
00817 
00818 
00819 static void
00820 sp_get_samples_3d(struct tgsi_sampler *sampler,
00821                   const float s[QUAD_SIZE],
00822                   const float t[QUAD_SIZE],
00823                   const float p[QUAD_SIZE],
00824                   float lodbias,
00825                   float rgba[NUM_CHANNELS][QUAD_SIZE])
00826 {
00827    /* get/map pipe_surfaces corresponding to 3D tex slices */
00828    unsigned level0, level1, j, imgFilter;
00829    int width, height, depth;
00830    float levelBlend;
00831    const uint face = 0;
00832 
00833    choose_mipmap_levels(sampler, s, t, p, lodbias,
00834                         &level0, &level1, &levelBlend, &imgFilter);
00835 
00836    assert(sampler->state->normalized_coords);
00837 
00838    width = sampler->texture->width[level0];
00839    height = sampler->texture->height[level0];
00840    depth = sampler->texture->depth[level0];
00841 
00842    assert(width > 0);
00843    assert(height > 0);
00844    assert(depth > 0);
00845 
00846    switch (imgFilter) {
00847    case PIPE_TEX_FILTER_NEAREST:
00848       for (j = 0; j < QUAD_SIZE; j++) {
00849          int x = nearest_texcoord(sampler->state->wrap_s, s[j], width);
00850          int y = nearest_texcoord(sampler->state->wrap_t, t[j], height);
00851          int z = nearest_texcoord(sampler->state->wrap_r, p[j], depth);
00852          get_texel(sampler, face, level0, x, y, z, rgba, j);
00853 
00854          if (level0 != level1) {
00855             /* get texels from second mipmap level and blend */
00856             float rgba2[4][4];
00857             unsigned c;
00858             x /= 2;
00859             y /= 2;
00860             z /= 2;
00861             get_texel(sampler, face, level1, x, y, z, rgba2, j);
00862             for (c = 0; c < NUM_CHANNELS; c++) {
00863                rgba[c][j] = LERP(levelBlend, rgba2[c][j], rgba[c][j]);
00864             }
00865          }
00866       }
00867       break;
00868    case PIPE_TEX_FILTER_LINEAR:
00869    case PIPE_TEX_FILTER_ANISO:
00870       for (j = 0; j < QUAD_SIZE; j++) {
00871          float texel0[4][4], texel1[4][4];
00872          float xw, yw, zw; /* interpolation weights */
00873          int x0, x1, y0, y1, z0, z1, c;
00874          linear_texcoord(sampler->state->wrap_s, s[j], width,  &x0, &x1, &xw);
00875          linear_texcoord(sampler->state->wrap_t, t[j], height, &y0, &y1, &yw);
00876          linear_texcoord(sampler->state->wrap_r, p[j], depth,  &z0, &z1, &zw);
00877          get_texel(sampler, face, level0, x0, y0, z0, texel0, 0);
00878          get_texel(sampler, face, level0, x1, y0, z0, texel0, 1);
00879          get_texel(sampler, face, level0, x0, y1, z0, texel0, 2);
00880          get_texel(sampler, face, level0, x1, y1, z0, texel0, 3);
00881          get_texel(sampler, face, level0, x0, y0, z1, texel1, 0);
00882          get_texel(sampler, face, level0, x1, y0, z1, texel1, 1);
00883          get_texel(sampler, face, level0, x0, y1, z1, texel1, 2);
00884          get_texel(sampler, face, level0, x1, y1, z1, texel1, 3);
00885 
00886          /* 3D lerp */
00887          for (c = 0; c < 4; c++) {
00888             float ctemp0[4][4], ctemp1[4][4];
00889             ctemp0[c][j] = lerp_2d(xw, yw,
00890                                    texel0[c][0], texel0[c][1],
00891                                    texel0[c][2], texel0[c][3]);
00892             ctemp1[c][j] = lerp_2d(xw, yw,
00893                                    texel1[c][0], texel1[c][1],
00894                                    texel1[c][2], texel1[c][3]);
00895             rgba[c][j] = LERP(zw, ctemp0[c][j], ctemp1[c][j]);
00896          }
00897 
00898          if (level0 != level1) {
00899             /* get texels from second mipmap level and blend */
00900             float rgba2[4][4];
00901             x0 /= 2;
00902             y0 /= 2;
00903             z0 /= 2;
00904             x1 /= 2;
00905             y1 /= 2;
00906             z1 /= 2;
00907             get_texel(sampler, face, level1, x0, y0, z0, texel0, 0);
00908             get_texel(sampler, face, level1, x1, y0, z0, texel0, 1);
00909             get_texel(sampler, face, level1, x0, y1, z0, texel0, 2);
00910             get_texel(sampler, face, level1, x1, y1, z0, texel0, 3);
00911             get_texel(sampler, face, level1, x0, y0, z1, texel1, 0);
00912             get_texel(sampler, face, level1, x1, y0, z1, texel1, 1);
00913             get_texel(sampler, face, level1, x0, y1, z1, texel1, 2);
00914             get_texel(sampler, face, level1, x1, y1, z1, texel1, 3);
00915 
00916             /* 3D lerp */
00917             for (c = 0; c < 4; c++) {
00918                float ctemp0[4][4], ctemp1[4][4];
00919                ctemp0[c][j] = lerp_2d(xw, yw,
00920                                       texel0[c][0], texel0[c][1],
00921                                       texel0[c][2], texel0[c][3]);
00922                ctemp1[c][j] = lerp_2d(xw, yw,
00923                                       texel1[c][0], texel1[c][1],
00924                                       texel1[c][2], texel1[c][3]);
00925                rgba2[c][j] = LERP(zw, ctemp0[c][j], ctemp1[c][j]);
00926             }
00927 
00928             /* blend mipmap levels */
00929             for (c = 0; c < NUM_CHANNELS; c++) {
00930                rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
00931             }
00932          }
00933       }
00934       break;
00935    default:
00936       assert(0);
00937    }
00938 }
00939 
00940 
00941 static void
00942 sp_get_samples_cube(struct tgsi_sampler *sampler,
00943                     const float s[QUAD_SIZE],
00944                     const float t[QUAD_SIZE],
00945                     const float p[QUAD_SIZE],
00946                     float lodbias,
00947                     float rgba[NUM_CHANNELS][QUAD_SIZE])
00948 {
00949    unsigned faces[QUAD_SIZE], j;
00950    float ssss[4], tttt[4];
00951    for (j = 0; j < QUAD_SIZE; j++) {
00952       faces[j] = choose_cube_face(s[j], t[j], p[j], ssss + j, tttt + j);
00953    }
00954    sp_get_samples_2d_common(sampler, ssss, tttt, NULL, lodbias, rgba, faces);
00955 }
00956 
00957 
00958 static void
00959 sp_get_samples_rect(struct tgsi_sampler *sampler,
00960                     const float s[QUAD_SIZE],
00961                     const float t[QUAD_SIZE],
00962                     const float p[QUAD_SIZE],
00963                     float lodbias,
00964                     float rgba[NUM_CHANNELS][QUAD_SIZE])
00965 {
00966    //sp_get_samples_2d_common(sampler, s, t, p, lodbias, rgba, faces);
00967    static const uint face = 0;
00968    const uint compare_func = sampler->state->compare_func;
00969    unsigned level0, level1, j, imgFilter;
00970    int width, height;
00971    float levelBlend;
00972 
00973    choose_mipmap_levels(sampler, s, t, p, lodbias,
00974                         &level0, &level1, &levelBlend, &imgFilter);
00975 
00976    /* texture RECTS cannot be mipmapped */
00977    assert(level0 == level1);
00978 
00979    width = sampler->texture->width[level0];
00980    height = sampler->texture->height[level0];
00981 
00982    assert(width > 0);
00983 
00984    switch (imgFilter) {
00985    case PIPE_TEX_FILTER_NEAREST:
00986       for (j = 0; j < QUAD_SIZE; j++) {
00987          int x = nearest_texcoord_unnorm(sampler->state->wrap_s, s[j], width);
00988          int y = nearest_texcoord_unnorm(sampler->state->wrap_t, t[j], height);
00989          get_texel(sampler, face, level0, x, y, 0, rgba, j);
00990          if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
00991             shadow_compare(compare_func, rgba, p, j);
00992          }
00993       }
00994       break;
00995    case PIPE_TEX_FILTER_LINEAR:
00996    case PIPE_TEX_FILTER_ANISO:
00997       for (j = 0; j < QUAD_SIZE; j++) {
00998          float tx[4][4], a, b;
00999          int x0, y0, x1, y1, c;
01000          linear_texcoord_unnorm(sampler->state->wrap_s, s[j], width,  &x0, &x1, &a);
01001          linear_texcoord_unnorm(sampler->state->wrap_t, t[j], height, &y0, &y1, &b);
01002          get_texel(sampler, face, level0, x0, y0, 0, tx, 0);
01003          get_texel(sampler, face, level0, x1, y0, 0, tx, 1);
01004          get_texel(sampler, face, level0, x0, y1, 0, tx, 2);
01005          get_texel(sampler, face, level0, x1, y1, 0, tx, 3);
01006          if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
01007             shadow_compare(compare_func, tx, p, 0);
01008             shadow_compare(compare_func, tx, p, 1);
01009             shadow_compare(compare_func, tx, p, 2);
01010             shadow_compare(compare_func, tx, p, 3);
01011          }
01012 
01013          for (c = 0; c < 4; c++) {
01014             rgba[c][j] = lerp_2d(a, b, tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
01015          }
01016       }
01017       break;
01018    default:
01019       assert(0);
01020    }
01021 }
01022 
01023 
01024 
01025 
01038 void
01039 sp_get_samples(struct tgsi_sampler *sampler,
01040                const float s[QUAD_SIZE],
01041                const float t[QUAD_SIZE],
01042                const float p[QUAD_SIZE],
01043                float lodbias,
01044                float rgba[NUM_CHANNELS][QUAD_SIZE])
01045 {
01046    if (!sampler->texture)
01047       return;
01048 
01049    switch (sampler->texture->target) {
01050    case PIPE_TEXTURE_1D:
01051       assert(sampler->state->normalized_coords);
01052       sp_get_samples_1d(sampler, s, t, p, lodbias, rgba);
01053       break;
01054    case PIPE_TEXTURE_2D:
01055       if (sampler->state->normalized_coords)
01056          sp_get_samples_2d(sampler, s, t, p, lodbias, rgba);
01057       else
01058          sp_get_samples_rect(sampler, s, t, p, lodbias, rgba);
01059       break;
01060    case PIPE_TEXTURE_3D:
01061       assert(sampler->state->normalized_coords);
01062       sp_get_samples_3d(sampler, s, t, p, lodbias, rgba);
01063       break;
01064    case PIPE_TEXTURE_CUBE:
01065       assert(sampler->state->normalized_coords);
01066       sp_get_samples_cube(sampler, s, t, p, lodbias, rgba);
01067       break;
01068    default:
01069       assert(0);
01070    }
01071 
01072 #if 0 /* DEBUG */
01073    {
01074       int i;
01075       printf("Sampled at %f, %f, %f:\n", s[0], t[0], p[0]);
01076       for (i = 0; i < 4; i++) {
01077          printf("Frag %d: %f %f %f %f\n", i,
01078                 rgba[0][i],
01079                 rgba[1][i],
01080                 rgba[2][i],
01081                 rgba[3][i]);
01082       }
01083    }
01084 #endif
01085 }
01086 

Generated on Tue Sep 29 06:25:17 2009 for Gallium3D by  doxygen 1.5.4