sp_tex_sample.c revision ae2195caf56d2eb782475254c68858a25ee7c857
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/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
335/**
336 * For RECT textures / unnormalized texcoords
337 * Only a subset of wrap modes supported.
338 */
339static INLINE int
340nearest_texcoord_unnorm(unsigned wrapMode, float s, unsigned size)
341{
342   int i;
343   switch (wrapMode) {
344   case PIPE_TEX_WRAP_CLAMP:
345      i = ifloor(s);
346      return CLAMP(i, 0, (int) size-1);
347   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
348      /* fall-through */
349   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
350      return ifloor( CLAMP(s, 0.5F, (float) size - 0.5F) );
351   default:
352      assert(0);
353      return 0;
354   }
355}
356
357
358/**
359 * For RECT textures / unnormalized texcoords.
360 * Only a subset of wrap modes supported.
361 */
362static INLINE void
363linear_texcoord_unnorm(unsigned wrapMode, float s, unsigned size,
364                       int *i0, int *i1, float *a)
365{
366   switch (wrapMode) {
367   case PIPE_TEX_WRAP_CLAMP:
368      /* Not exactly what the spec says, but it matches NVIDIA output */
369      s = CLAMP(s - 0.5F, 0.0f, (float) size - 1.0f);
370      *i0 = ifloor(s);
371      *i1 = *i0 + 1;
372      break;
373   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
374      /* fall-through */
375   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
376      s = CLAMP(s, 0.5F, (float) size - 0.5F);
377      s -= 0.5F;
378      *i0 = ifloor(s);
379      *i1 = *i0 + 1;
380      if (*i1 > (int) size - 1)
381         *i1 = size - 1;
382      break;
383   default:
384      assert(0);
385   }
386   *a = FRAC(s);
387}
388
389
390static unsigned
391choose_cube_face(float rx, float ry, float rz, float *newS, float *newT)
392{
393   /*
394      major axis
395      direction     target                             sc     tc    ma
396      ----------    -------------------------------    ---    ---   ---
397       +rx          TEXTURE_CUBE_MAP_POSITIVE_X_EXT    -rz    -ry   rx
398       -rx          TEXTURE_CUBE_MAP_NEGATIVE_X_EXT    +rz    -ry   rx
399       +ry          TEXTURE_CUBE_MAP_POSITIVE_Y_EXT    +rx    +rz   ry
400       -ry          TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT    +rx    -rz   ry
401       +rz          TEXTURE_CUBE_MAP_POSITIVE_Z_EXT    +rx    -ry   rz
402       -rz          TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT    -rx    -ry   rz
403   */
404   const float arx = FABSF(rx), ary = FABSF(ry), arz = FABSF(rz);
405   unsigned face;
406   float sc, tc, ma;
407
408   if (arx > ary && arx > arz) {
409      if (rx >= 0.0F) {
410         face = PIPE_TEX_FACE_POS_X;
411         sc = -rz;
412         tc = -ry;
413         ma = arx;
414      }
415      else {
416         face = PIPE_TEX_FACE_NEG_X;
417         sc = rz;
418         tc = -ry;
419         ma = arx;
420      }
421   }
422   else if (ary > arx && ary > arz) {
423      if (ry >= 0.0F) {
424         face = PIPE_TEX_FACE_POS_Y;
425         sc = rx;
426         tc = rz;
427         ma = ary;
428      }
429      else {
430         face = PIPE_TEX_FACE_NEG_Y;
431         sc = rx;
432         tc = -rz;
433         ma = ary;
434      }
435   }
436   else {
437      if (rz > 0.0F) {
438         face = PIPE_TEX_FACE_POS_Z;
439         sc = rx;
440         tc = -ry;
441         ma = arz;
442      }
443      else {
444         face = PIPE_TEX_FACE_NEG_Z;
445         sc = -rx;
446         tc = -ry;
447         ma = arz;
448      }
449   }
450
451   *newS = ( sc / ma + 1.0F ) * 0.5F;
452   *newT = ( tc / ma + 1.0F ) * 0.5F;
453
454   return face;
455}
456
457
458/**
459 * Examine the quad's texture coordinates to compute the partial
460 * derivatives w.r.t X and Y, then compute lambda (level of detail).
461 *
462 * This is only done for fragment shaders, not vertex shaders.
463 */
464static float
465compute_lambda(struct tgsi_sampler *sampler,
466               const float s[QUAD_SIZE],
467               const float t[QUAD_SIZE],
468               const float p[QUAD_SIZE],
469               float lodbias)
470{
471   float rho, lambda;
472
473   assert(sampler->state->normalized_coords);
474
475   assert(s);
476   {
477      float dsdx = s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT];
478      float dsdy = s[QUAD_TOP_LEFT]     - s[QUAD_BOTTOM_LEFT];
479      dsdx = FABSF(dsdx);
480      dsdy = FABSF(dsdy);
481      rho = MAX2(dsdx, dsdy) * sampler->texture->width[0];
482   }
483   if (t) {
484      float dtdx = t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT];
485      float dtdy = t[QUAD_TOP_LEFT]     - t[QUAD_BOTTOM_LEFT];
486      float max;
487      dtdx = FABSF(dtdx);
488      dtdy = FABSF(dtdy);
489      max = MAX2(dtdx, dtdy) * sampler->texture->height[0];
490      rho = MAX2(rho, max);
491   }
492   if (p) {
493      float dpdx = p[QUAD_BOTTOM_RIGHT] - p[QUAD_BOTTOM_LEFT];
494      float dpdy = p[QUAD_TOP_LEFT]     - p[QUAD_BOTTOM_LEFT];
495      float max;
496      dpdx = FABSF(dpdx);
497      dpdy = FABSF(dpdy);
498      max = MAX2(dpdx, dpdy) * sampler->texture->depth[0];
499      rho = MAX2(rho, max);
500   }
501
502   lambda = LOG2(rho);
503   lambda += lodbias + sampler->state->lod_bias;
504   lambda = CLAMP(lambda, sampler->state->min_lod, sampler->state->max_lod);
505
506   return lambda;
507}
508
509
510/**
511 * Do several things here:
512 * 1. Compute lambda from the texcoords, if needed
513 * 2. Determine if we're minifying or magnifying
514 * 3. If minifying, choose mipmap levels
515 * 4. Return image filter to use within mipmap images
516 */
517static void
518choose_mipmap_levels(struct tgsi_sampler *sampler,
519                     const float s[QUAD_SIZE],
520                     const float t[QUAD_SIZE],
521                     const float p[QUAD_SIZE],
522                     float lodbias,
523                     unsigned *level0, unsigned *level1, float *levelBlend,
524                     unsigned *imgFilter)
525{
526   if (sampler->state->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) {
527      /* no mipmap selection needed */
528      *level0 = *level1 = CLAMP((int) sampler->state->min_lod,
529                                0, (int) sampler->texture->last_level);
530
531      if (sampler->state->min_img_filter != sampler->state->mag_img_filter) {
532         /* non-mipmapped texture, but still need to determine if doing
533          * minification or magnification.
534          */
535         float lambda = compute_lambda(sampler, s, t, p, lodbias);
536         if (lambda <= 0.0) {
537            *imgFilter = sampler->state->mag_img_filter;
538         }
539         else {
540            *imgFilter = sampler->state->min_img_filter;
541         }
542      }
543      else {
544         *imgFilter = sampler->state->mag_img_filter;
545      }
546   }
547   else {
548      float lambda;
549
550      if (1)
551         /* fragment shader */
552         lambda = compute_lambda(sampler, s, t, p, lodbias);
553      else
554         /* vertex shader */
555         lambda = lodbias; /* not really a bias, but absolute LOD */
556
557      if (lambda <= 0.0) { /* XXX threshold depends on the filter */
558         /* magnifying */
559         *imgFilter = sampler->state->mag_img_filter;
560         *level0 = *level1 = 0;
561      }
562      else {
563         /* minifying */
564         *imgFilter = sampler->state->min_img_filter;
565
566         /* choose mipmap level(s) and compute the blend factor between them */
567         if (sampler->state->min_mip_filter == PIPE_TEX_MIPFILTER_NEAREST) {
568            /* Nearest mipmap level */
569            const int lvl = (int) (lambda + 0.5);
570            *level0 =
571            *level1 = CLAMP(lvl, 0, (int) sampler->texture->last_level);
572         }
573         else {
574            /* Linear interpolation between mipmap levels */
575            const int lvl = (int) lambda;
576            *level0 = CLAMP(lvl,     0, (int) sampler->texture->last_level);
577            *level1 = CLAMP(lvl + 1, 0, (int) sampler->texture->last_level);
578            *levelBlend = FRAC(lambda);  /* blending weight between levels */
579         }
580      }
581   }
582}
583
584
585/**
586 * Get a texel from a texture, using the texture tile cache.
587 *
588 * \param face  the cube face in 0..5
589 * \param level  the mipmap level
590 * \param x  the x coord of texel within 2D image
591 * \param y  the y coord of texel within 2D image
592 * \param z  which slice of a 3D texture
593 * \param rgba  the quad to put the texel/color into
594 * \param j  which element of the rgba quad to write to
595 *
596 * XXX maybe move this into sp_tile_cache.c and merge with the
597 * sp_get_cached_tile_tex() function.  Also, get 4 texels instead of 1...
598 */
599static void
600get_texel(struct tgsi_sampler *sampler,
601          unsigned face, unsigned level, int x, int y, int z,
602          float rgba[NUM_CHANNELS][QUAD_SIZE], unsigned j)
603{
604   if (x < 0 || x >= (int) sampler->texture->width[level] ||
605       y < 0 || y >= (int) sampler->texture->height[level] ||
606       z < 0 || z >= (int) sampler->texture->depth[level]) {
607      rgba[0][j] = sampler->state->border_color[0];
608      rgba[1][j] = sampler->state->border_color[1];
609      rgba[2][j] = sampler->state->border_color[2];
610      rgba[3][j] = sampler->state->border_color[3];
611   }
612   else {
613      const int tx = x % TILE_SIZE;
614      const int ty = y % TILE_SIZE;
615      const struct softpipe_cached_tile *tile
616         = sp_get_cached_tile_tex(sampler->pipe, sampler->cache,
617                                  x, y, z, face, level);
618      rgba[0][j] = tile->data.color[ty][tx][0];
619      rgba[1][j] = tile->data.color[ty][tx][1];
620      rgba[2][j] = tile->data.color[ty][tx][2];
621      rgba[3][j] = tile->data.color[ty][tx][3];
622      if (0)
623      {
624         char fmt[100];
625         pf_sprint_name( fmt, sampler->texture->format);
626         debug_printf("Get texel %f %f %f %f from %s\n",
627                      rgba[0][j], rgba[1][j], rgba[2][j], rgba[3][j], fmt);
628      }
629   }
630}
631
632
633/**
634 * Compare texcoord 'p' (aka R) against texture value 'rgba[0]'
635 * When we sampled the depth texture, the depth value was put into all
636 * RGBA channels.  We look at the red channel here.
637 */
638static INLINE void
639shadow_compare(uint compare_func,
640               float rgba[NUM_CHANNELS][QUAD_SIZE],
641               const float p[QUAD_SIZE],
642               uint j)
643{
644   int k;
645   switch (compare_func) {
646   case PIPE_FUNC_LESS:
647      k = p[j] < rgba[0][j];
648      break;
649   case PIPE_FUNC_LEQUAL:
650      k = p[j] <= rgba[0][j];
651      break;
652   case PIPE_FUNC_GREATER:
653      k = p[j] > rgba[0][j];
654      break;
655   case PIPE_FUNC_GEQUAL:
656      k = p[j] >= rgba[0][j];
657      break;
658   case PIPE_FUNC_EQUAL:
659      k = p[j] == rgba[0][j];
660      break;
661   case PIPE_FUNC_NOTEQUAL:
662      k = p[j] != rgba[0][j];
663      break;
664   case PIPE_FUNC_ALWAYS:
665      k = 1;
666      break;
667   case PIPE_FUNC_NEVER:
668      k = 0;
669      break;
670   default:
671      k = 0;
672      assert(0);
673      break;
674   }
675
676   rgba[0][j] = rgba[1][j] = rgba[2][j] = (float) k;
677}
678
679
680/**
681 * Common code for sampling 1D/2D/cube textures.
682 * Could probably extend for 3D...
683 */
684static void
685sp_get_samples_2d_common(struct tgsi_sampler *sampler,
686                         const float s[QUAD_SIZE],
687                         const float t[QUAD_SIZE],
688                         const float p[QUAD_SIZE],
689                         float lodbias,
690                         float rgba[NUM_CHANNELS][QUAD_SIZE],
691                         const unsigned faces[4])
692{
693   const uint compare_func = sampler->state->compare_func;
694   unsigned level0, level1, j, imgFilter;
695   int width, height;
696   float levelBlend;
697
698   choose_mipmap_levels(sampler, s, t, p, lodbias,
699                        &level0, &level1, &levelBlend, &imgFilter);
700
701   assert(sampler->state->normalized_coords);
702
703   width = sampler->texture->width[level0];
704   height = sampler->texture->height[level0];
705
706   assert(width > 0);
707
708   switch (imgFilter) {
709   case PIPE_TEX_FILTER_NEAREST:
710      for (j = 0; j < QUAD_SIZE; j++) {
711         int x = nearest_texcoord(sampler->state->wrap_s, s[j], width);
712         int y = nearest_texcoord(sampler->state->wrap_t, t[j], height);
713         get_texel(sampler, faces[j], level0, x, y, 0, rgba, j);
714         if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
715            shadow_compare(compare_func, rgba, p, j);
716         }
717
718         if (level0 != level1) {
719            /* get texels from second mipmap level and blend */
720            float rgba2[4][4];
721            unsigned c;
722            x = x / 2;
723            y = y / 2;
724            get_texel(sampler, faces[j], level1, x, y, 0, rgba2, j);
725            if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
726               shadow_compare(compare_func, rgba2, p, j);
727            }
728
729            for (c = 0; c < NUM_CHANNELS; c++) {
730               rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
731            }
732         }
733      }
734      break;
735   case PIPE_TEX_FILTER_LINEAR:
736   case PIPE_TEX_FILTER_ANISO:
737      for (j = 0; j < QUAD_SIZE; j++) {
738         float tx[4][4], a, b;
739         int x0, y0, x1, y1, c;
740         linear_texcoord(sampler->state->wrap_s, s[j], width,  &x0, &x1, &a);
741         linear_texcoord(sampler->state->wrap_t, t[j], height, &y0, &y1, &b);
742         get_texel(sampler, faces[j], level0, x0, y0, 0, tx, 0);
743         get_texel(sampler, faces[j], level0, x1, y0, 0, tx, 1);
744         get_texel(sampler, faces[j], level0, x0, y1, 0, tx, 2);
745         get_texel(sampler, faces[j], level0, x1, y1, 0, tx, 3);
746         if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
747            shadow_compare(compare_func, tx, p, 0);
748            shadow_compare(compare_func, tx, p, 1);
749            shadow_compare(compare_func, tx, p, 2);
750            shadow_compare(compare_func, tx, p, 3);
751         }
752
753         for (c = 0; c < 4; c++) {
754            rgba[c][j] = lerp_2d(a, b, tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
755         }
756
757         if (level0 != level1) {
758            /* get texels from second mipmap level and blend */
759            float rgba2[4][4];
760            x0 = x0 / 2;
761            y0 = y0 / 2;
762            x1 = x1 / 2;
763            y1 = y1 / 2;
764            get_texel(sampler, faces[j], level1, x0, y0, 0, tx, 0);
765            get_texel(sampler, faces[j], level1, x1, y0, 0, tx, 1);
766            get_texel(sampler, faces[j], level1, x0, y1, 0, tx, 2);
767            get_texel(sampler, faces[j], level1, x1, y1, 0, tx, 3);
768            if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
769               shadow_compare(compare_func, tx, p, 0);
770               shadow_compare(compare_func, tx, p, 1);
771               shadow_compare(compare_func, tx, p, 2);
772               shadow_compare(compare_func, tx, p, 3);
773            }
774
775            for (c = 0; c < 4; c++) {
776               rgba2[c][j] = lerp_2d(a, b,
777                                     tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
778            }
779
780            for (c = 0; c < NUM_CHANNELS; c++) {
781               rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
782            }
783         }
784      }
785      break;
786   default:
787      assert(0);
788   }
789}
790
791
792static void
793sp_get_samples_1d(struct tgsi_sampler *sampler,
794                  const float s[QUAD_SIZE],
795                  const float t[QUAD_SIZE],
796                  const float p[QUAD_SIZE],
797                  float lodbias,
798                  float rgba[NUM_CHANNELS][QUAD_SIZE])
799{
800   static const unsigned faces[4] = {0, 0, 0, 0};
801   static const float tzero[4] = {0, 0, 0, 0};
802   sp_get_samples_2d_common(sampler, s, tzero, NULL, lodbias, rgba, faces);
803}
804
805
806static void
807sp_get_samples_2d(struct tgsi_sampler *sampler,
808                  const float s[QUAD_SIZE],
809                  const float t[QUAD_SIZE],
810                  const float p[QUAD_SIZE],
811                  float lodbias,
812                  float rgba[NUM_CHANNELS][QUAD_SIZE])
813{
814   static const unsigned faces[4] = {0, 0, 0, 0};
815   sp_get_samples_2d_common(sampler, s, t, p, lodbias, rgba, faces);
816}
817
818
819static void
820sp_get_samples_3d(struct tgsi_sampler *sampler,
821                  const float s[QUAD_SIZE],
822                  const float t[QUAD_SIZE],
823                  const float p[QUAD_SIZE],
824                  float lodbias,
825                  float rgba[NUM_CHANNELS][QUAD_SIZE])
826{
827   /* get/map pipe_surfaces corresponding to 3D tex slices */
828   unsigned level0, level1, j, imgFilter;
829   int width, height, depth;
830   float levelBlend;
831   const uint face = 0;
832
833   choose_mipmap_levels(sampler, s, t, p, lodbias,
834                        &level0, &level1, &levelBlend, &imgFilter);
835
836   assert(sampler->state->normalized_coords);
837
838   width = sampler->texture->width[level0];
839   height = sampler->texture->height[level0];
840   depth = sampler->texture->depth[level0];
841
842   assert(width > 0);
843   assert(height > 0);
844   assert(depth > 0);
845
846   switch (imgFilter) {
847   case PIPE_TEX_FILTER_NEAREST:
848      for (j = 0; j < QUAD_SIZE; j++) {
849         int x = nearest_texcoord(sampler->state->wrap_s, s[j], width);
850         int y = nearest_texcoord(sampler->state->wrap_t, t[j], height);
851         int z = nearest_texcoord(sampler->state->wrap_r, p[j], depth);
852         get_texel(sampler, face, level0, x, y, z, rgba, j);
853
854         if (level0 != level1) {
855            /* get texels from second mipmap level and blend */
856            float rgba2[4][4];
857            unsigned c;
858            x /= 2;
859            y /= 2;
860            z /= 2;
861            get_texel(sampler, face, level1, x, y, z, rgba2, j);
862            for (c = 0; c < NUM_CHANNELS; c++) {
863               rgba[c][j] = LERP(levelBlend, rgba2[c][j], rgba[c][j]);
864            }
865         }
866      }
867      break;
868   case PIPE_TEX_FILTER_LINEAR:
869   case PIPE_TEX_FILTER_ANISO:
870      for (j = 0; j < QUAD_SIZE; j++) {
871         float texel0[4][4], texel1[4][4];
872         float xw, yw, zw; /* interpolation weights */
873         int x0, x1, y0, y1, z0, z1, c;
874         linear_texcoord(sampler->state->wrap_s, s[j], width,  &x0, &x1, &xw);
875         linear_texcoord(sampler->state->wrap_t, t[j], height, &y0, &y1, &yw);
876         linear_texcoord(sampler->state->wrap_r, p[j], depth,  &z0, &z1, &zw);
877         get_texel(sampler, face, level0, x0, y0, z0, texel0, 0);
878         get_texel(sampler, face, level0, x1, y0, z0, texel0, 1);
879         get_texel(sampler, face, level0, x0, y1, z0, texel0, 2);
880         get_texel(sampler, face, level0, x1, y1, z0, texel0, 3);
881         get_texel(sampler, face, level0, x0, y0, z1, texel1, 0);
882         get_texel(sampler, face, level0, x1, y0, z1, texel1, 1);
883         get_texel(sampler, face, level0, x0, y1, z1, texel1, 2);
884         get_texel(sampler, face, level0, x1, y1, z1, texel1, 3);
885
886         /* 3D lerp */
887         for (c = 0; c < 4; c++) {
888            float ctemp0[4][4], ctemp1[4][4];
889            ctemp0[c][j] = lerp_2d(xw, yw,
890                                   texel0[c][0], texel0[c][1],
891                                   texel0[c][2], texel0[c][3]);
892            ctemp1[c][j] = lerp_2d(xw, yw,
893                                   texel1[c][0], texel1[c][1],
894                                   texel1[c][2], texel1[c][3]);
895            rgba[c][j] = LERP(zw, ctemp0[c][j], ctemp1[c][j]);
896         }
897
898         if (level0 != level1) {
899            /* get texels from second mipmap level and blend */
900            float rgba2[4][4];
901            x0 /= 2;
902            y0 /= 2;
903            z0 /= 2;
904            x1 /= 2;
905            y1 /= 2;
906            z1 /= 2;
907            get_texel(sampler, face, level1, x0, y0, z0, texel0, 0);
908            get_texel(sampler, face, level1, x1, y0, z0, texel0, 1);
909            get_texel(sampler, face, level1, x0, y1, z0, texel0, 2);
910            get_texel(sampler, face, level1, x1, y1, z0, texel0, 3);
911            get_texel(sampler, face, level1, x0, y0, z1, texel1, 0);
912            get_texel(sampler, face, level1, x1, y0, z1, texel1, 1);
913            get_texel(sampler, face, level1, x0, y1, z1, texel1, 2);
914            get_texel(sampler, face, level1, x1, y1, z1, texel1, 3);
915
916            /* 3D lerp */
917            for (c = 0; c < 4; c++) {
918               float ctemp0[4][4], ctemp1[4][4];
919               ctemp0[c][j] = lerp_2d(xw, yw,
920                                      texel0[c][0], texel0[c][1],
921                                      texel0[c][2], texel0[c][3]);
922               ctemp1[c][j] = lerp_2d(xw, yw,
923                                      texel1[c][0], texel1[c][1],
924                                      texel1[c][2], texel1[c][3]);
925               rgba2[c][j] = LERP(zw, ctemp0[c][j], ctemp1[c][j]);
926            }
927
928            /* blend mipmap levels */
929            for (c = 0; c < NUM_CHANNELS; c++) {
930               rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
931            }
932         }
933      }
934      break;
935   default:
936      assert(0);
937   }
938}
939
940
941static void
942sp_get_samples_cube(struct tgsi_sampler *sampler,
943                    const float s[QUAD_SIZE],
944                    const float t[QUAD_SIZE],
945                    const float p[QUAD_SIZE],
946                    float lodbias,
947                    float rgba[NUM_CHANNELS][QUAD_SIZE])
948{
949   unsigned faces[QUAD_SIZE], j;
950   float ssss[4], tttt[4];
951   for (j = 0; j < QUAD_SIZE; j++) {
952      faces[j] = choose_cube_face(s[j], t[j], p[j], ssss + j, tttt + j);
953   }
954   sp_get_samples_2d_common(sampler, ssss, tttt, NULL, lodbias, rgba, faces);
955}
956
957
958static void
959sp_get_samples_rect(struct tgsi_sampler *sampler,
960                    const float s[QUAD_SIZE],
961                    const float t[QUAD_SIZE],
962                    const float p[QUAD_SIZE],
963                    float lodbias,
964                    float rgba[NUM_CHANNELS][QUAD_SIZE])
965{
966   //sp_get_samples_2d_common(sampler, s, t, p, lodbias, rgba, faces);
967   static const uint face = 0;
968   const uint compare_func = sampler->state->compare_func;
969   unsigned level0, level1, j, imgFilter;
970   int width, height;
971   float levelBlend;
972
973   choose_mipmap_levels(sampler, s, t, p, lodbias,
974                        &level0, &level1, &levelBlend, &imgFilter);
975
976   /* texture RECTS cannot be mipmapped */
977   assert(level0 == level1);
978
979   width = sampler->texture->width[level0];
980   height = sampler->texture->height[level0];
981
982   assert(width > 0);
983
984   switch (imgFilter) {
985   case PIPE_TEX_FILTER_NEAREST:
986      for (j = 0; j < QUAD_SIZE; j++) {
987         int x = nearest_texcoord_unnorm(sampler->state->wrap_s, s[j], width);
988         int y = nearest_texcoord_unnorm(sampler->state->wrap_t, t[j], height);
989         get_texel(sampler, face, level0, x, y, 0, rgba, j);
990         if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
991            shadow_compare(compare_func, rgba, p, j);
992         }
993      }
994      break;
995   case PIPE_TEX_FILTER_LINEAR:
996   case PIPE_TEX_FILTER_ANISO:
997      for (j = 0; j < QUAD_SIZE; j++) {
998         float tx[4][4], a, b;
999         int x0, y0, x1, y1, c;
1000         linear_texcoord_unnorm(sampler->state->wrap_s, s[j], width,  &x0, &x1, &a);
1001         linear_texcoord_unnorm(sampler->state->wrap_t, t[j], height, &y0, &y1, &b);
1002         get_texel(sampler, face, level0, x0, y0, 0, tx, 0);
1003         get_texel(sampler, face, level0, x1, y0, 0, tx, 1);
1004         get_texel(sampler, face, level0, x0, y1, 0, tx, 2);
1005         get_texel(sampler, face, level0, x1, y1, 0, tx, 3);
1006         if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
1007            shadow_compare(compare_func, tx, p, 0);
1008            shadow_compare(compare_func, tx, p, 1);
1009            shadow_compare(compare_func, tx, p, 2);
1010            shadow_compare(compare_func, tx, p, 3);
1011         }
1012
1013         for (c = 0; c < 4; c++) {
1014            rgba[c][j] = lerp_2d(a, b, tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
1015         }
1016      }
1017      break;
1018   default:
1019      assert(0);
1020   }
1021}
1022
1023
1024
1025
1026/**
1027 * Called via tgsi_sampler::get_samples()
1028 * Use the sampler's state setting to get a filtered RGBA value
1029 * from the sampler's texture.
1030 *
1031 * XXX we can implement many versions of this function, each
1032 * tightly coded for a specific combination of sampler state
1033 * (nearest + repeat), (bilinear mipmap + clamp), etc.
1034 *
1035 * The update_samplers() function in st_atom_sampler.c could create
1036 * a new tgsi_sampler object for each state combo it finds....
1037 */
1038void
1039sp_get_samples(struct tgsi_sampler *sampler,
1040               const float s[QUAD_SIZE],
1041               const float t[QUAD_SIZE],
1042               const float p[QUAD_SIZE],
1043               float lodbias,
1044               float rgba[NUM_CHANNELS][QUAD_SIZE])
1045{
1046   if (!sampler->texture)
1047      return;
1048
1049   switch (sampler->texture->target) {
1050   case PIPE_TEXTURE_1D:
1051      assert(sampler->state->normalized_coords);
1052      sp_get_samples_1d(sampler, s, t, p, lodbias, rgba);
1053      break;
1054   case PIPE_TEXTURE_2D:
1055      if (sampler->state->normalized_coords)
1056         sp_get_samples_2d(sampler, s, t, p, lodbias, rgba);
1057      else
1058         sp_get_samples_rect(sampler, s, t, p, lodbias, rgba);
1059      break;
1060   case PIPE_TEXTURE_3D:
1061      assert(sampler->state->normalized_coords);
1062      sp_get_samples_3d(sampler, s, t, p, lodbias, rgba);
1063      break;
1064   case PIPE_TEXTURE_CUBE:
1065      assert(sampler->state->normalized_coords);
1066      sp_get_samples_cube(sampler, s, t, p, lodbias, rgba);
1067      break;
1068   default:
1069      assert(0);
1070   }
1071
1072#if 0 /* DEBUG */
1073   {
1074      int i;
1075      printf("Sampled at %f, %f, %f:\n", s[0], t[0], p[0]);
1076      for (i = 0; i < 4; i++) {
1077         printf("Frag %d: %f %f %f %f\n", i,
1078                rgba[0][i],
1079                rgba[1][i],
1080                rgba[2][i],
1081                rgba[3][i]);
1082      }
1083   }
1084#endif
1085}
1086
1087