sp_tex_sample.c revision 0c6bbd41bd6dc1041eaca7c907d3768d107c1afa
1/**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28/**
29 * Texture sampling
30 *
31 * Authors:
32 *   Brian Paul
33 */
34
35#include "sp_context.h"
36#include "sp_headers.h"
37#include "sp_surface.h"
38#include "sp_tex_sample.h"
39#include "sp_tile_cache.h"
40#include "pipe/p_context.h"
41#include "pipe/p_defines.h"
42#include "pipe/p_util.h"
43#include "tgsi/exec/tgsi_exec.h"
44
45
46/*
47 * Note, the FRAC macro has to work perfectly.  Otherwise you'll sometimes
48 * see 1-pixel bands of improperly weighted linear-filtered textures.
49 * The tests/texwrap.c demo is a good test.
50 * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
51 * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
52 */
53#define FRAC(f)  ((f) - ifloor(f))
54
55
56/**
57 * Linear interpolation macro
58 */
59#define LERP(T, A, B)  ( (A) + (T) * ((B) - (A)) )
60
61
62/**
63 * Do 2D/biliner interpolation of float values.
64 * v00, v10, v01 and v11 are typically four texture samples in a square/box.
65 * a and b are the horizontal and vertical interpolants.
66 * It's important that this function is inlined when compiled with
67 * optimization!  If we find that's not true on some systems, convert
68 * to a macro.
69 */
70static INLINE float
71lerp_2d(float a, float b,
72        float v00, float v10, float v01, float v11)
73{
74   const float temp0 = LERP(a, v00, v10);
75   const float temp1 = LERP(a, v01, v11);
76   return LERP(b, temp0, temp1);
77}
78
79
80/**
81 * If A is a signed integer, A % B doesn't give the right value for A < 0
82 * (in terms of texture repeat).  Just casting to unsigned fixes that.
83 */
84#define REMAINDER(A, B) ((unsigned) (A) % (unsigned) (B))
85
86
87/**
88 * Apply texture coord wrapping mode and return integer texture index.
89 * \param wrapMode  PIPE_TEX_WRAP_x
90 * \param s  the texcoord
91 * \param size  the texture image size
92 * \return  integer texture index
93 */
94static INLINE int
95nearest_texcoord(unsigned wrapMode, float s, unsigned size)
96{
97   int i;
98   switch (wrapMode) {
99   case PIPE_TEX_WRAP_REPEAT:
100      /* s limited to [0,1) */
101      /* i limited to [0,size-1] */
102      i = ifloor(s * size);
103      i = REMAINDER(i, size);
104      return i;
105   case PIPE_TEX_WRAP_CLAMP:
106      /* s limited to [0,1] */
107      /* i limited to [0,size-1] */
108      if (s <= 0.0F)
109         i = 0;
110      else if (s >= 1.0F)
111         i = size - 1;
112      else
113         i = ifloor(s * size);
114      return i;
115   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
116      {
117         /* s limited to [min,max] */
118         /* i limited to [0, size-1] */
119         const float min = 1.0F / (2.0F * size);
120         const float max = 1.0F - min;
121         if (s < min)
122            i = 0;
123         else if (s > max)
124            i = size - 1;
125         else
126            i = ifloor(s * size);
127      }
128      return i;
129   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
130      {
131         /* s limited to [min,max] */
132         /* i limited to [-1, size] */
133         const float min = -1.0F / (2.0F * size);
134         const float max = 1.0F - min;
135         if (s <= min)
136            i = -1;
137         else if (s >= max)
138            i = size;
139         else
140            i = ifloor(s * size);
141      }
142      return i;
143   case PIPE_TEX_WRAP_MIRROR_REPEAT:
144      {
145         const float min = 1.0F / (2.0F * size);
146         const float max = 1.0F - min;
147         const int flr = ifloor(s);
148         float u;
149         if (flr & 1)
150            u = 1.0F - (s - (float) flr);
151         else
152            u = s - (float) flr;
153         if (u < min)
154            i = 0;
155         else if (u > max)
156            i = size - 1;
157         else
158            i = ifloor(u * size);
159      }
160      return i;
161   case PIPE_TEX_WRAP_MIRROR_CLAMP:
162      {
163         /* s limited to [0,1] */
164         /* i limited to [0,size-1] */
165         const float u = FABSF(s);
166         if (u <= 0.0F)
167            i = 0;
168         else if (u >= 1.0F)
169            i = size - 1;
170         else
171            i = ifloor(u * size);
172      }
173      return i;
174   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
175      {
176         /* s limited to [min,max] */
177         /* i limited to [0, size-1] */
178         const float min = 1.0F / (2.0F * size);
179         const float max = 1.0F - min;
180         const float u = FABSF(s);
181         if (u < min)
182            i = 0;
183         else if (u > max)
184            i = size - 1;
185         else
186            i = ifloor(u * size);
187      }
188      return i;
189   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
190      {
191         /* s limited to [min,max] */
192         /* i limited to [0, size-1] */
193         const float min = -1.0F / (2.0F * size);
194         const float max = 1.0F - min;
195         const float u = FABSF(s);
196         if (u < min)
197            i = -1;
198         else if (u > max)
199            i = size;
200         else
201            i = ifloor(u * size);
202      }
203      return i;
204   default:
205      assert(0);
206      return 0;
207   }
208}
209
210
211/**
212 * Used to compute texel locations for linear sampling.
213 * \param wrapMode  PIPE_TEX_WRAP_x
214 * \param s  the texcoord
215 * \param size  the texture image size
216 * \param i0  returns first texture index
217 * \param i1  returns second texture index (usually *i0 + 1)
218 * \param a  returns blend factor/weight between texture indexes
219 */
220static INLINE void
221linear_texcoord(unsigned wrapMode, float s, unsigned size,
222                int *i0, int *i1, float *a)
223{
224   float u;
225   switch (wrapMode) {
226   case PIPE_TEX_WRAP_REPEAT:
227      u = s * size - 0.5F;
228      *i0 = REMAINDER(ifloor(u), size);
229      *i1 = REMAINDER(*i0 + 1, size);
230      break;
231   case PIPE_TEX_WRAP_CLAMP:
232      if (s <= 0.0F)
233         u = 0.0F;
234      else if (s >= 1.0F)
235         u = (float) size;
236      else
237         u = s * size;
238      u -= 0.5F;
239      *i0 = ifloor(u);
240      *i1 = *i0 + 1;
241      break;
242   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
243      if (s <= 0.0F)
244         u = 0.0F;
245      else if (s >= 1.0F)
246         u = (float) size;
247      else
248         u = s * size;
249      u -= 0.5F;
250      *i0 = ifloor(u);
251      *i1 = *i0 + 1;
252      if (*i0 < 0)
253         *i0 = 0;
254      if (*i1 >= (int) size)
255         *i1 = size - 1;
256      break;
257   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
258      {
259         const float min = -1.0F / (2.0F * size);
260         const float max = 1.0F - min;
261         if (s <= min)
262            u = min * size;
263         else if (s >= max)
264            u = max * size;
265         else
266            u = s * size;
267         u -= 0.5F;
268         *i0 = ifloor(u);
269         *i1 = *i0 + 1;
270      }
271      break;
272   case PIPE_TEX_WRAP_MIRROR_REPEAT:
273      {
274         const int flr = ifloor(s);
275         if (flr & 1)
276            u = 1.0F - (s - (float) flr);
277         else
278            u = s - (float) flr;
279         u = (u * size) - 0.5F;
280         *i0 = ifloor(u);
281         *i1 = *i0 + 1;
282         if (*i0 < 0)
283            *i0 = 0;
284         if (*i1 >= (int) size)
285            *i1 = size - 1;
286      }
287      break;
288   case PIPE_TEX_WRAP_MIRROR_CLAMP:
289      u = FABSF(s);
290      if (u >= 1.0F)
291         u = (float) size;
292      else
293         u *= size;
294      u -= 0.5F;
295      *i0 = ifloor(u);
296      *i1 = *i0 + 1;
297      break;
298   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
299      u = FABSF(s);
300      if (u >= 1.0F)
301         u = (float) size;
302      else
303         u *= size;
304      u -= 0.5F;
305      *i0 = ifloor(u);
306      *i1 = *i0 + 1;
307      if (*i0 < 0)
308         *i0 = 0;
309      if (*i1 >= (int) size)
310         *i1 = size - 1;
311      break;
312   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
313      {
314         const float min = -1.0F / (2.0F * size);
315         const float max = 1.0F - min;
316         u = FABSF(s);
317         if (u <= min)
318            u = min * size;
319         else if (u >= max)
320            u = max * size;
321         else
322            u *= size;
323         u -= 0.5F;
324         *i0 = ifloor(u);
325         *i1 = *i0 + 1;
326      }
327      break;
328   default:
329      assert(0);
330   }
331   *a = FRAC(u);
332}
333
334
335static unsigned
336choose_cube_face(float rx, float ry, float rz, float *newS, float *newT)
337{
338   /*
339      major axis
340      direction     target                             sc     tc    ma
341      ----------    -------------------------------    ---    ---   ---
342       +rx          TEXTURE_CUBE_MAP_POSITIVE_X_EXT    -rz    -ry   rx
343       -rx          TEXTURE_CUBE_MAP_NEGATIVE_X_EXT    +rz    -ry   rx
344       +ry          TEXTURE_CUBE_MAP_POSITIVE_Y_EXT    +rx    +rz   ry
345       -ry          TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT    +rx    -rz   ry
346       +rz          TEXTURE_CUBE_MAP_POSITIVE_Z_EXT    +rx    -ry   rz
347       -rz          TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT    -rx    -ry   rz
348   */
349   const float arx = FABSF(rx), ary = FABSF(ry), arz = FABSF(rz);
350   unsigned face;
351   float sc, tc, ma;
352
353   if (arx > ary && arx > arz) {
354      if (rx >= 0.0F) {
355         face = PIPE_TEX_FACE_POS_X;
356         sc = -rz;
357         tc = -ry;
358         ma = arx;
359      }
360      else {
361         face = PIPE_TEX_FACE_NEG_X;
362         sc = rz;
363         tc = -ry;
364         ma = arx;
365      }
366   }
367   else if (ary > arx && ary > arz) {
368      if (ry >= 0.0F) {
369         face = PIPE_TEX_FACE_POS_Y;
370         sc = rx;
371         tc = rz;
372         ma = ary;
373      }
374      else {
375         face = PIPE_TEX_FACE_NEG_Y;
376         sc = rx;
377         tc = -rz;
378         ma = ary;
379      }
380   }
381   else {
382      if (rz > 0.0F) {
383         face = PIPE_TEX_FACE_POS_Z;
384         sc = rx;
385         tc = -ry;
386         ma = arz;
387      }
388      else {
389         face = PIPE_TEX_FACE_NEG_Z;
390         sc = -rx;
391         tc = -ry;
392         ma = arz;
393      }
394   }
395
396   *newS = ( sc / ma + 1.0F ) * 0.5F;
397   *newT = ( tc / ma + 1.0F ) * 0.5F;
398
399   return face;
400}
401
402
403/**
404 * Examine the quad's texture coordinates to compute the partial
405 * derivatives w.r.t X and Y, then compute lambda (level of detail).
406 *
407 * This is only done for fragment shaders, not vertex shaders.
408 */
409static float
410compute_lambda(struct tgsi_sampler *sampler,
411               const float s[QUAD_SIZE],
412               const float t[QUAD_SIZE],
413               const float p[QUAD_SIZE],
414               float lodbias)
415{
416   float rho, lambda;
417
418   assert(s);
419   {
420      float dsdx = s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT];
421      float dsdy = s[QUAD_TOP_LEFT]     - s[QUAD_BOTTOM_LEFT];
422      dsdx = FABSF(dsdx);
423      dsdy = FABSF(dsdy);
424      rho = MAX2(dsdx, dsdy);
425      if (sampler->state->normalized_coords)
426         rho *= sampler->texture->width[0];
427   }
428   if (t) {
429      float dtdx = t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT];
430      float dtdy = t[QUAD_TOP_LEFT]     - t[QUAD_BOTTOM_LEFT];
431      float max;
432      dtdx = FABSF(dtdx);
433      dtdy = FABSF(dtdy);
434      max = MAX2(dtdx, dtdy);
435      if (sampler->state->normalized_coords)
436         max *= sampler->texture->height[0];
437      rho = MAX2(rho, max);
438   }
439   if (p) {
440      float dpdx = p[QUAD_BOTTOM_RIGHT] - p[QUAD_BOTTOM_LEFT];
441      float dpdy = p[QUAD_TOP_LEFT]     - p[QUAD_BOTTOM_LEFT];
442      float max;
443      dpdx = FABSF(dpdx);
444      dpdy = FABSF(dpdy);
445      max = MAX2(dpdx, dpdy);
446      if (sampler->state->normalized_coords)
447         max *= sampler->texture->depth[0];
448      rho = MAX2(rho, max);
449   }
450
451   lambda = LOG2(rho);
452   lambda += lodbias + sampler->state->lod_bias;
453   lambda = CLAMP(lambda, sampler->state->min_lod, sampler->state->max_lod);
454
455   return lambda;
456}
457
458
459/**
460 * Do several things here:
461 * 1. Compute lambda from the texcoords, if needed
462 * 2. Determine if we're minifying or magnifying
463 * 3. If minifying, choose mipmap levels
464 * 4. Return image filter to use within mipmap images
465 */
466static void
467choose_mipmap_levels(struct tgsi_sampler *sampler,
468                     const float s[QUAD_SIZE],
469                     const float t[QUAD_SIZE],
470                     const float p[QUAD_SIZE],
471                     float lodbias,
472                     unsigned *level0, unsigned *level1, float *levelBlend,
473                     unsigned *imgFilter)
474{
475   if (sampler->state->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) {
476      /* no mipmap selection needed */
477      *level0 = *level1 = CLAMP((int) sampler->state->min_lod,
478                                0, (int) sampler->texture->last_level);
479
480      if (sampler->state->min_img_filter != sampler->state->mag_img_filter) {
481         /* non-mipmapped texture, but still need to determine if doing
482          * minification or magnification.
483          */
484         float lambda = compute_lambda(sampler, s, t, p, lodbias);
485         if (lambda <= 0.0) {
486            *imgFilter = sampler->state->mag_img_filter;
487         }
488         else {
489            *imgFilter = sampler->state->min_img_filter;
490         }
491      }
492      else {
493         *imgFilter = sampler->state->mag_img_filter;
494      }
495   }
496   else {
497      float lambda;
498
499      if (1)
500         /* fragment shader */
501         lambda = compute_lambda(sampler, s, t, p, lodbias);
502      else
503         /* vertex shader */
504         lambda = lodbias; /* not really a bias, but absolute LOD */
505
506      if (lambda <= 0.0) { /* XXX threshold depends on the filter */
507         /* magnifying */
508         *imgFilter = sampler->state->mag_img_filter;
509         *level0 = *level1 = 0;
510      }
511      else {
512         /* minifying */
513         *imgFilter = sampler->state->min_img_filter;
514
515         /* choose mipmap level(s) and compute the blend factor between them */
516         if (sampler->state->min_mip_filter == PIPE_TEX_MIPFILTER_NEAREST) {
517            /* Nearest mipmap level */
518            const int lvl = (int) (lambda + 0.5);
519            *level0 =
520            *level1 = CLAMP(lvl, 0, (int) sampler->texture->last_level);
521         }
522         else {
523            /* Linear interpolation between mipmap levels */
524            const int lvl = (int) lambda;
525            *level0 = CLAMP(lvl,     0, (int) sampler->texture->last_level);
526            *level1 = CLAMP(lvl + 1, 0, (int) sampler->texture->last_level);
527            *levelBlend = FRAC(lambda);  /* blending weight between levels */
528         }
529      }
530   }
531}
532
533
534/**
535 * Get a texel from a texture, using the texture tile cache.
536 *
537 * \param face  the cube face in 0..5
538 * \param level  the mipmap level
539 * \param x  the x coord of texel within 2D image
540 * \param y  the y coord of texel within 2D image
541 * \param z  which slice of a 3D texture
542 * \param rgba  the quad to put the texel/color into
543 * \param j  which element of the rgba quad to write to
544 *
545 * XXX maybe move this into sp_tile_cache.c and merge with the
546 * sp_get_cached_tile_tex() function.  Also, get 4 texels instead of 1...
547 */
548static void
549get_texel(struct tgsi_sampler *sampler,
550          unsigned face, unsigned level, int x, int y, int z,
551          float rgba[NUM_CHANNELS][QUAD_SIZE], unsigned j)
552{
553   const int tx = x % TILE_SIZE;
554   const int ty = y % TILE_SIZE;
555   const struct softpipe_cached_tile *tile
556      = sp_get_cached_tile_tex(sampler->pipe, sampler->cache,
557                               x, y, z, face, level);
558   rgba[0][j] = tile->data.color[ty][tx][0];
559   rgba[1][j] = tile->data.color[ty][tx][1];
560   rgba[2][j] = tile->data.color[ty][tx][2];
561   rgba[3][j] = tile->data.color[ty][tx][3];
562}
563
564
565/**
566 * Compare texcoord 'p' (aka R) against texture value 'rgba[0]'
567 * When we sampled the depth texture, the depth value was put into all
568 * RGBA channels.  We look at the red channel here.
569 */
570static INLINE void
571shadow_compare(uint compare_func,
572               float rgba[NUM_CHANNELS][QUAD_SIZE],
573               const float p[QUAD_SIZE],
574               uint j)
575{
576   int k;
577   switch (compare_func) {
578   case PIPE_FUNC_LESS:
579      k = p[j] < rgba[0][j];
580      break;
581   case PIPE_FUNC_LEQUAL:
582      k = p[j] <= rgba[0][j];
583      break;
584   case PIPE_FUNC_GREATER:
585      k = p[j] > rgba[0][j];
586      break;
587   case PIPE_FUNC_GEQUAL:
588      k = p[j] >= rgba[0][j];
589      break;
590   case PIPE_FUNC_EQUAL:
591      k = p[j] == rgba[0][j];
592      break;
593   case PIPE_FUNC_NOTEQUAL:
594      k = p[j] != rgba[0][j];
595      break;
596   case PIPE_FUNC_ALWAYS:
597      k = 1;
598      break;
599   case PIPE_FUNC_NEVER:
600      k = 0;
601      break;
602   default:
603      assert(0);
604   }
605
606   rgba[0][j] = rgba[1][j] = rgba[2][j] = (float) k;
607}
608
609
610/**
611 * Common code for sampling 1D/2D/cube textures.
612 * Could probably extend for 3D...
613 */
614static void
615sp_get_samples_2d_common(struct tgsi_sampler *sampler,
616                         const float s[QUAD_SIZE],
617                         const float t[QUAD_SIZE],
618                         const float p[QUAD_SIZE],
619                         float lodbias,
620                         float rgba[NUM_CHANNELS][QUAD_SIZE],
621                         const unsigned faces[4])
622{
623   const uint compare_func = sampler->state->compare_func;
624   unsigned level0, level1, j, imgFilter;
625   int width, height;
626   float levelBlend;
627
628   choose_mipmap_levels(sampler, s, t, p, lodbias,
629                        &level0, &level1, &levelBlend, &imgFilter);
630
631   if (sampler->state->normalized_coords) {
632      width = sampler->texture->width[level0];
633      height = sampler->texture->height[level0];
634   }
635   else {
636      width = height = 1;
637   }
638
639   assert(width > 0);
640
641   switch (imgFilter) {
642   case PIPE_TEX_FILTER_NEAREST:
643      for (j = 0; j < QUAD_SIZE; j++) {
644         int x = nearest_texcoord(sampler->state->wrap_s, s[j], width);
645         int y = nearest_texcoord(sampler->state->wrap_t, t[j], height);
646         get_texel(sampler, faces[j], level0, x, y, 0, rgba, j);
647         if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
648            shadow_compare(compare_func, rgba, p, j);
649         }
650
651         if (level0 != level1) {
652            /* get texels from second mipmap level and blend */
653            float rgba2[4][4];
654            unsigned c;
655            x = x / 2;
656            y = y / 2;
657            get_texel(sampler, faces[j], level1, x, y, 0, rgba2, j);
658            if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
659               shadow_compare(compare_func, rgba2, p, j);
660            }
661
662            for (c = 0; c < NUM_CHANNELS; c++) {
663               rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
664            }
665         }
666      }
667      break;
668   case PIPE_TEX_FILTER_LINEAR:
669      for (j = 0; j < QUAD_SIZE; j++) {
670         float tx[4][4], a, b;
671         int x0, y0, x1, y1, c;
672         linear_texcoord(sampler->state->wrap_s, s[j], width,  &x0, &x1, &a);
673         linear_texcoord(sampler->state->wrap_t, t[j], height, &y0, &y1, &b);
674         get_texel(sampler, faces[j], level0, x0, y0, 0, tx, 0);
675         get_texel(sampler, faces[j], level0, x1, y0, 0, tx, 1);
676         get_texel(sampler, faces[j], level0, x0, y1, 0, tx, 2);
677         get_texel(sampler, faces[j], level0, x1, y1, 0, tx, 3);
678         if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
679            shadow_compare(compare_func, tx, p, 0);
680            shadow_compare(compare_func, tx, p, 1);
681            shadow_compare(compare_func, tx, p, 2);
682            shadow_compare(compare_func, tx, p, 3);
683         }
684
685         for (c = 0; c < 4; c++) {
686            rgba[c][j] = lerp_2d(a, b, tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
687         }
688
689         if (level0 != level1) {
690            /* get texels from second mipmap level and blend */
691            float rgba2[4][4];
692            x0 = x0 / 2;
693            y0 = y0 / 2;
694            x1 = x1 / 2;
695            y1 = y1 / 2;
696            get_texel(sampler, faces[j], level1, x0, y0, 0, tx, 0);
697            get_texel(sampler, faces[j], level1, x1, y0, 0, tx, 1);
698            get_texel(sampler, faces[j], level1, x0, y1, 0, tx, 2);
699            get_texel(sampler, faces[j], level1, x1, y1, 0, tx, 3);
700            if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
701               shadow_compare(compare_func, tx, p, 0);
702               shadow_compare(compare_func, tx, p, 1);
703               shadow_compare(compare_func, tx, p, 2);
704               shadow_compare(compare_func, tx, p, 3);
705            }
706
707            for (c = 0; c < 4; c++) {
708               rgba2[c][j] = lerp_2d(a, b,
709                                     tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
710            }
711
712            for (c = 0; c < NUM_CHANNELS; c++) {
713               rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
714            }
715         }
716      }
717      break;
718   default:
719      assert(0);
720   }
721}
722
723
724static void
725sp_get_samples_1d(struct tgsi_sampler *sampler,
726                  const float s[QUAD_SIZE],
727                  const float t[QUAD_SIZE],
728                  const float p[QUAD_SIZE],
729                  float lodbias,
730                  float rgba[NUM_CHANNELS][QUAD_SIZE])
731{
732   static const unsigned faces[4] = {0, 0, 0, 0};
733   static const float tzero[4] = {0, 0, 0, 0};
734   sp_get_samples_2d_common(sampler, s, tzero, NULL, lodbias, rgba, faces);
735}
736
737
738static void
739sp_get_samples_2d(struct tgsi_sampler *sampler,
740                  const float s[QUAD_SIZE],
741                  const float t[QUAD_SIZE],
742                  const float p[QUAD_SIZE],
743                  float lodbias,
744                  float rgba[NUM_CHANNELS][QUAD_SIZE])
745{
746   static const unsigned faces[4] = {0, 0, 0, 0};
747   sp_get_samples_2d_common(sampler, s, t, p, lodbias, rgba, faces);
748}
749
750
751static void
752sp_get_samples_3d(struct tgsi_sampler *sampler,
753                  const float s[QUAD_SIZE],
754                  const float t[QUAD_SIZE],
755                  const float p[QUAD_SIZE],
756                  float lodbias,
757                  float rgba[NUM_CHANNELS][QUAD_SIZE])
758{
759   /* get/map pipe_surfaces corresponding to 3D tex slices */
760   unsigned level0, level1, j, imgFilter;
761   int width, height, depth;
762   float levelBlend;
763   const uint face = 0;
764
765   choose_mipmap_levels(sampler, s, t, p, lodbias,
766                        &level0, &level1, &levelBlend, &imgFilter);
767
768   if (sampler->state->normalized_coords) {
769      width = sampler->texture->width[level0];
770      height = sampler->texture->height[level0];
771      depth = sampler->texture->depth[level0];
772   }
773   else {
774      width = height = depth = 1;
775   }
776
777   assert(width > 0);
778   assert(height > 0);
779   assert(depth > 0);
780
781   switch (imgFilter) {
782   case PIPE_TEX_FILTER_NEAREST:
783      for (j = 0; j < QUAD_SIZE; j++) {
784         int x = nearest_texcoord(sampler->state->wrap_s, s[j], width);
785         int y = nearest_texcoord(sampler->state->wrap_t, t[j], height);
786         int z = nearest_texcoord(sampler->state->wrap_r, p[j], depth);
787         get_texel(sampler, face, level0, x, y, z, rgba, j);
788
789         if (level0 != level1) {
790            /* get texels from second mipmap level and blend */
791            float rgba2[4][4];
792            unsigned c;
793            x /= 2;
794            y /= 2;
795            z /= 2;
796            get_texel(sampler, face, level1, x, y, z, rgba2, j);
797            for (c = 0; c < NUM_CHANNELS; c++) {
798               rgba[c][j] = LERP(levelBlend, rgba2[c][j], rgba[c][j]);
799            }
800         }
801      }
802      break;
803   case PIPE_TEX_FILTER_LINEAR:
804      for (j = 0; j < QUAD_SIZE; j++) {
805         float texel0[4][4], texel1[4][4];
806         float xw, yw, zw; /* interpolation weights */
807         int x0, x1, y0, y1, z0, z1, c;
808         linear_texcoord(sampler->state->wrap_s, s[j], width,  &x0, &x1, &xw);
809         linear_texcoord(sampler->state->wrap_t, t[j], height, &y0, &y1, &yw);
810         linear_texcoord(sampler->state->wrap_r, p[j], depth,  &z0, &z1, &zw);
811         get_texel(sampler, face, level0, x0, y0, z0, texel0, 0);
812         get_texel(sampler, face, level0, x1, y0, z0, texel0, 1);
813         get_texel(sampler, face, level0, x0, y1, z0, texel0, 2);
814         get_texel(sampler, face, level0, x1, y1, z0, texel0, 3);
815         get_texel(sampler, face, level0, x0, y0, z1, texel1, 0);
816         get_texel(sampler, face, level0, x1, y0, z1, texel1, 1);
817         get_texel(sampler, face, level0, x0, y1, z1, texel1, 2);
818         get_texel(sampler, face, level0, x1, y1, z1, texel1, 3);
819
820         /* 3D lerp */
821         for (c = 0; c < 4; c++) {
822            float ctemp0[4][4], ctemp1[4][4];
823            ctemp0[c][j] = lerp_2d(xw, yw,
824                                   texel0[c][0], texel0[c][1],
825                                   texel0[c][2], texel0[c][3]);
826            ctemp1[c][j] = lerp_2d(xw, yw,
827                                   texel1[c][0], texel1[c][1],
828                                   texel1[c][2], texel1[c][3]);
829            rgba[c][j] = LERP(zw, ctemp0[c][j], ctemp1[c][j]);
830         }
831
832         if (level0 != level1) {
833            /* get texels from second mipmap level and blend */
834            float rgba2[4][4];
835            x0 /= 2;
836            y0 /= 2;
837            z0 /= 2;
838            x1 /= 2;
839            y1 /= 2;
840            z1 /= 2;
841            get_texel(sampler, face, level1, x0, y0, z0, texel0, 0);
842            get_texel(sampler, face, level1, x1, y0, z0, texel0, 1);
843            get_texel(sampler, face, level1, x0, y1, z0, texel0, 2);
844            get_texel(sampler, face, level1, x1, y1, z0, texel0, 3);
845            get_texel(sampler, face, level1, x0, y0, z1, texel1, 0);
846            get_texel(sampler, face, level1, x1, y0, z1, texel1, 1);
847            get_texel(sampler, face, level1, x0, y1, z1, texel1, 2);
848            get_texel(sampler, face, level1, x1, y1, z1, texel1, 3);
849
850            /* 3D lerp */
851            for (c = 0; c < 4; c++) {
852               float ctemp0[4][4], ctemp1[4][4];
853               ctemp0[c][j] = lerp_2d(xw, yw,
854                                      texel0[c][0], texel0[c][1],
855                                      texel0[c][2], texel0[c][3]);
856               ctemp1[c][j] = lerp_2d(xw, yw,
857                                      texel1[c][0], texel1[c][1],
858                                      texel1[c][2], texel1[c][3]);
859               rgba2[c][j] = LERP(zw, ctemp0[c][j], ctemp1[c][j]);
860            }
861
862            /* blend mipmap levels */
863            for (c = 0; c < NUM_CHANNELS; c++) {
864               rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
865            }
866         }
867      }
868      break;
869   default:
870      assert(0);
871   }
872}
873
874
875static void
876sp_get_samples_cube(struct tgsi_sampler *sampler,
877                    const float s[QUAD_SIZE],
878                    const float t[QUAD_SIZE],
879                    const float p[QUAD_SIZE],
880                    float lodbias,
881                    float rgba[NUM_CHANNELS][QUAD_SIZE])
882{
883   unsigned faces[QUAD_SIZE], j;
884   float ssss[4], tttt[4];
885   for (j = 0; j < QUAD_SIZE; j++) {
886      faces[j] = choose_cube_face(s[j], t[j], p[j], ssss + j, tttt + j);
887   }
888   sp_get_samples_2d_common(sampler, ssss, tttt, NULL, lodbias, rgba, faces);
889}
890
891
892/**
893 * Called via tgsi_sampler::get_samples()
894 * Use the sampler's state setting to get a filtered RGBA value
895 * from the sampler's texture.
896 *
897 * XXX we can implement many versions of this function, each
898 * tightly coded for a specific combination of sampler state
899 * (nearest + repeat), (bilinear mipmap + clamp), etc.
900 *
901 * The update_samplers() function in st_atom_sampler.c could create
902 * a new tgsi_sampler object for each state combo it finds....
903 */
904void
905sp_get_samples(struct tgsi_sampler *sampler,
906               const float s[QUAD_SIZE],
907               const float t[QUAD_SIZE],
908               const float p[QUAD_SIZE],
909               float lodbias,
910               float rgba[NUM_CHANNELS][QUAD_SIZE])
911{
912   if (!sampler->texture)
913      return;
914
915   switch (sampler->texture->target) {
916   case PIPE_TEXTURE_1D:
917      sp_get_samples_1d(sampler, s, t, p, lodbias, rgba);
918      break;
919   case PIPE_TEXTURE_2D:
920      sp_get_samples_2d(sampler, s, t, p, lodbias, rgba);
921      break;
922   case PIPE_TEXTURE_3D:
923      sp_get_samples_3d(sampler, s, t, p, lodbias, rgba);
924      break;
925   case PIPE_TEXTURE_CUBE:
926      sp_get_samples_cube(sampler, s, t, p, lodbias, rgba);
927      break;
928   default:
929      assert(0);
930   }
931}
932
933