sp_tex_sample.c revision d50d7a54de89e602a9951264878dfe06924e1adb
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   }
623}
624
625
626/**
627 * Compare texcoord 'p' (aka R) against texture value 'rgba[0]'
628 * When we sampled the depth texture, the depth value was put into all
629 * RGBA channels.  We look at the red channel here.
630 */
631static INLINE void
632shadow_compare(uint compare_func,
633               float rgba[NUM_CHANNELS][QUAD_SIZE],
634               const float p[QUAD_SIZE],
635               uint j)
636{
637   int k;
638   switch (compare_func) {
639   case PIPE_FUNC_LESS:
640      k = p[j] < rgba[0][j];
641      break;
642   case PIPE_FUNC_LEQUAL:
643      k = p[j] <= rgba[0][j];
644      break;
645   case PIPE_FUNC_GREATER:
646      k = p[j] > rgba[0][j];
647      break;
648   case PIPE_FUNC_GEQUAL:
649      k = p[j] >= rgba[0][j];
650      break;
651   case PIPE_FUNC_EQUAL:
652      k = p[j] == rgba[0][j];
653      break;
654   case PIPE_FUNC_NOTEQUAL:
655      k = p[j] != rgba[0][j];
656      break;
657   case PIPE_FUNC_ALWAYS:
658      k = 1;
659      break;
660   case PIPE_FUNC_NEVER:
661      k = 0;
662      break;
663   default:
664      k = 0;
665      assert(0);
666      break;
667   }
668
669   rgba[0][j] = rgba[1][j] = rgba[2][j] = (float) k;
670}
671
672
673/**
674 * Common code for sampling 1D/2D/cube textures.
675 * Could probably extend for 3D...
676 */
677static void
678sp_get_samples_2d_common(struct tgsi_sampler *sampler,
679                         const float s[QUAD_SIZE],
680                         const float t[QUAD_SIZE],
681                         const float p[QUAD_SIZE],
682                         float lodbias,
683                         float rgba[NUM_CHANNELS][QUAD_SIZE],
684                         const unsigned faces[4])
685{
686   const uint compare_func = sampler->state->compare_func;
687   unsigned level0, level1, j, imgFilter;
688   int width, height;
689   float levelBlend;
690
691   choose_mipmap_levels(sampler, s, t, p, lodbias,
692                        &level0, &level1, &levelBlend, &imgFilter);
693
694   assert(sampler->state->normalized_coords);
695
696   width = sampler->texture->width[level0];
697   height = sampler->texture->height[level0];
698
699   assert(width > 0);
700
701   switch (imgFilter) {
702   case PIPE_TEX_FILTER_NEAREST:
703      for (j = 0; j < QUAD_SIZE; j++) {
704         int x = nearest_texcoord(sampler->state->wrap_s, s[j], width);
705         int y = nearest_texcoord(sampler->state->wrap_t, t[j], height);
706         get_texel(sampler, faces[j], level0, x, y, 0, rgba, j);
707         if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
708            shadow_compare(compare_func, rgba, p, j);
709         }
710
711         if (level0 != level1) {
712            /* get texels from second mipmap level and blend */
713            float rgba2[4][4];
714            unsigned c;
715            x = x / 2;
716            y = y / 2;
717            get_texel(sampler, faces[j], level1, x, y, 0, rgba2, j);
718            if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
719               shadow_compare(compare_func, rgba2, p, j);
720            }
721
722            for (c = 0; c < NUM_CHANNELS; c++) {
723               rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
724            }
725         }
726      }
727      break;
728   case PIPE_TEX_FILTER_LINEAR:
729   case PIPE_TEX_FILTER_ANISO:
730      for (j = 0; j < QUAD_SIZE; j++) {
731         float tx[4][4], a, b;
732         int x0, y0, x1, y1, c;
733         linear_texcoord(sampler->state->wrap_s, s[j], width,  &x0, &x1, &a);
734         linear_texcoord(sampler->state->wrap_t, t[j], height, &y0, &y1, &b);
735         get_texel(sampler, faces[j], level0, x0, y0, 0, tx, 0);
736         get_texel(sampler, faces[j], level0, x1, y0, 0, tx, 1);
737         get_texel(sampler, faces[j], level0, x0, y1, 0, tx, 2);
738         get_texel(sampler, faces[j], level0, x1, y1, 0, tx, 3);
739         if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
740            shadow_compare(compare_func, tx, p, 0);
741            shadow_compare(compare_func, tx, p, 1);
742            shadow_compare(compare_func, tx, p, 2);
743            shadow_compare(compare_func, tx, p, 3);
744         }
745
746         for (c = 0; c < 4; c++) {
747            rgba[c][j] = lerp_2d(a, b, tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
748         }
749
750         if (level0 != level1) {
751            /* get texels from second mipmap level and blend */
752            float rgba2[4][4];
753            x0 = x0 / 2;
754            y0 = y0 / 2;
755            x1 = x1 / 2;
756            y1 = y1 / 2;
757            get_texel(sampler, faces[j], level1, x0, y0, 0, tx, 0);
758            get_texel(sampler, faces[j], level1, x1, y0, 0, tx, 1);
759            get_texel(sampler, faces[j], level1, x0, y1, 0, tx, 2);
760            get_texel(sampler, faces[j], level1, x1, y1, 0, tx, 3);
761            if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
762               shadow_compare(compare_func, tx, p, 0);
763               shadow_compare(compare_func, tx, p, 1);
764               shadow_compare(compare_func, tx, p, 2);
765               shadow_compare(compare_func, tx, p, 3);
766            }
767
768            for (c = 0; c < 4; c++) {
769               rgba2[c][j] = lerp_2d(a, b,
770                                     tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
771            }
772
773            for (c = 0; c < NUM_CHANNELS; c++) {
774               rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
775            }
776         }
777      }
778      break;
779   default:
780      assert(0);
781   }
782}
783
784
785static void
786sp_get_samples_1d(struct tgsi_sampler *sampler,
787                  const float s[QUAD_SIZE],
788                  const float t[QUAD_SIZE],
789                  const float p[QUAD_SIZE],
790                  float lodbias,
791                  float rgba[NUM_CHANNELS][QUAD_SIZE])
792{
793   static const unsigned faces[4] = {0, 0, 0, 0};
794   static const float tzero[4] = {0, 0, 0, 0};
795   sp_get_samples_2d_common(sampler, s, tzero, NULL, lodbias, rgba, faces);
796}
797
798
799static void
800sp_get_samples_2d(struct tgsi_sampler *sampler,
801                  const float s[QUAD_SIZE],
802                  const float t[QUAD_SIZE],
803                  const float p[QUAD_SIZE],
804                  float lodbias,
805                  float rgba[NUM_CHANNELS][QUAD_SIZE])
806{
807   static const unsigned faces[4] = {0, 0, 0, 0};
808   sp_get_samples_2d_common(sampler, s, t, p, lodbias, rgba, faces);
809}
810
811
812static void
813sp_get_samples_3d(struct tgsi_sampler *sampler,
814                  const float s[QUAD_SIZE],
815                  const float t[QUAD_SIZE],
816                  const float p[QUAD_SIZE],
817                  float lodbias,
818                  float rgba[NUM_CHANNELS][QUAD_SIZE])
819{
820   /* get/map pipe_surfaces corresponding to 3D tex slices */
821   unsigned level0, level1, j, imgFilter;
822   int width, height, depth;
823   float levelBlend;
824   const uint face = 0;
825
826   choose_mipmap_levels(sampler, s, t, p, lodbias,
827                        &level0, &level1, &levelBlend, &imgFilter);
828
829   assert(sampler->state->normalized_coords);
830
831   width = sampler->texture->width[level0];
832   height = sampler->texture->height[level0];
833   depth = sampler->texture->depth[level0];
834
835   assert(width > 0);
836   assert(height > 0);
837   assert(depth > 0);
838
839   switch (imgFilter) {
840   case PIPE_TEX_FILTER_NEAREST:
841      for (j = 0; j < QUAD_SIZE; j++) {
842         int x = nearest_texcoord(sampler->state->wrap_s, s[j], width);
843         int y = nearest_texcoord(sampler->state->wrap_t, t[j], height);
844         int z = nearest_texcoord(sampler->state->wrap_r, p[j], depth);
845         get_texel(sampler, face, level0, x, y, z, rgba, j);
846
847         if (level0 != level1) {
848            /* get texels from second mipmap level and blend */
849            float rgba2[4][4];
850            unsigned c;
851            x /= 2;
852            y /= 2;
853            z /= 2;
854            get_texel(sampler, face, level1, x, y, z, rgba2, j);
855            for (c = 0; c < NUM_CHANNELS; c++) {
856               rgba[c][j] = LERP(levelBlend, rgba2[c][j], rgba[c][j]);
857            }
858         }
859      }
860      break;
861   case PIPE_TEX_FILTER_LINEAR:
862   case PIPE_TEX_FILTER_ANISO:
863      for (j = 0; j < QUAD_SIZE; j++) {
864         float texel0[4][4], texel1[4][4];
865         float xw, yw, zw; /* interpolation weights */
866         int x0, x1, y0, y1, z0, z1, c;
867         linear_texcoord(sampler->state->wrap_s, s[j], width,  &x0, &x1, &xw);
868         linear_texcoord(sampler->state->wrap_t, t[j], height, &y0, &y1, &yw);
869         linear_texcoord(sampler->state->wrap_r, p[j], depth,  &z0, &z1, &zw);
870         get_texel(sampler, face, level0, x0, y0, z0, texel0, 0);
871         get_texel(sampler, face, level0, x1, y0, z0, texel0, 1);
872         get_texel(sampler, face, level0, x0, y1, z0, texel0, 2);
873         get_texel(sampler, face, level0, x1, y1, z0, texel0, 3);
874         get_texel(sampler, face, level0, x0, y0, z1, texel1, 0);
875         get_texel(sampler, face, level0, x1, y0, z1, texel1, 1);
876         get_texel(sampler, face, level0, x0, y1, z1, texel1, 2);
877         get_texel(sampler, face, level0, x1, y1, z1, texel1, 3);
878
879         /* 3D lerp */
880         for (c = 0; c < 4; c++) {
881            float ctemp0[4][4], ctemp1[4][4];
882            ctemp0[c][j] = lerp_2d(xw, yw,
883                                   texel0[c][0], texel0[c][1],
884                                   texel0[c][2], texel0[c][3]);
885            ctemp1[c][j] = lerp_2d(xw, yw,
886                                   texel1[c][0], texel1[c][1],
887                                   texel1[c][2], texel1[c][3]);
888            rgba[c][j] = LERP(zw, ctemp0[c][j], ctemp1[c][j]);
889         }
890
891         if (level0 != level1) {
892            /* get texels from second mipmap level and blend */
893            float rgba2[4][4];
894            x0 /= 2;
895            y0 /= 2;
896            z0 /= 2;
897            x1 /= 2;
898            y1 /= 2;
899            z1 /= 2;
900            get_texel(sampler, face, level1, x0, y0, z0, texel0, 0);
901            get_texel(sampler, face, level1, x1, y0, z0, texel0, 1);
902            get_texel(sampler, face, level1, x0, y1, z0, texel0, 2);
903            get_texel(sampler, face, level1, x1, y1, z0, texel0, 3);
904            get_texel(sampler, face, level1, x0, y0, z1, texel1, 0);
905            get_texel(sampler, face, level1, x1, y0, z1, texel1, 1);
906            get_texel(sampler, face, level1, x0, y1, z1, texel1, 2);
907            get_texel(sampler, face, level1, x1, y1, z1, texel1, 3);
908
909            /* 3D lerp */
910            for (c = 0; c < 4; c++) {
911               float ctemp0[4][4], ctemp1[4][4];
912               ctemp0[c][j] = lerp_2d(xw, yw,
913                                      texel0[c][0], texel0[c][1],
914                                      texel0[c][2], texel0[c][3]);
915               ctemp1[c][j] = lerp_2d(xw, yw,
916                                      texel1[c][0], texel1[c][1],
917                                      texel1[c][2], texel1[c][3]);
918               rgba2[c][j] = LERP(zw, ctemp0[c][j], ctemp1[c][j]);
919            }
920
921            /* blend mipmap levels */
922            for (c = 0; c < NUM_CHANNELS; c++) {
923               rgba[c][j] = LERP(levelBlend, rgba[c][j], rgba2[c][j]);
924            }
925         }
926      }
927      break;
928   default:
929      assert(0);
930   }
931}
932
933
934static void
935sp_get_samples_cube(struct tgsi_sampler *sampler,
936                    const float s[QUAD_SIZE],
937                    const float t[QUAD_SIZE],
938                    const float p[QUAD_SIZE],
939                    float lodbias,
940                    float rgba[NUM_CHANNELS][QUAD_SIZE])
941{
942   unsigned faces[QUAD_SIZE], j;
943   float ssss[4], tttt[4];
944   for (j = 0; j < QUAD_SIZE; j++) {
945      faces[j] = choose_cube_face(s[j], t[j], p[j], ssss + j, tttt + j);
946   }
947   sp_get_samples_2d_common(sampler, ssss, tttt, NULL, lodbias, rgba, faces);
948}
949
950
951static void
952sp_get_samples_rect(struct tgsi_sampler *sampler,
953                    const float s[QUAD_SIZE],
954                    const float t[QUAD_SIZE],
955                    const float p[QUAD_SIZE],
956                    float lodbias,
957                    float rgba[NUM_CHANNELS][QUAD_SIZE])
958{
959   //sp_get_samples_2d_common(sampler, s, t, p, lodbias, rgba, faces);
960   static const uint face = 0;
961   const uint compare_func = sampler->state->compare_func;
962   unsigned level0, level1, j, imgFilter;
963   int width, height;
964   float levelBlend;
965
966   choose_mipmap_levels(sampler, s, t, p, lodbias,
967                        &level0, &level1, &levelBlend, &imgFilter);
968
969   /* texture RECTS cannot be mipmapped */
970   assert(level0 == level1);
971
972   width = sampler->texture->width[level0];
973   height = sampler->texture->height[level0];
974
975   assert(width > 0);
976
977   switch (imgFilter) {
978   case PIPE_TEX_FILTER_NEAREST:
979      for (j = 0; j < QUAD_SIZE; j++) {
980         int x = nearest_texcoord_unnorm(sampler->state->wrap_s, s[j], width);
981         int y = nearest_texcoord_unnorm(sampler->state->wrap_t, t[j], height);
982         get_texel(sampler, face, level0, x, y, 0, rgba, j);
983         if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
984            shadow_compare(compare_func, rgba, p, j);
985         }
986      }
987      break;
988   case PIPE_TEX_FILTER_LINEAR:
989   case PIPE_TEX_FILTER_ANISO:
990      for (j = 0; j < QUAD_SIZE; j++) {
991         float tx[4][4], a, b;
992         int x0, y0, x1, y1, c;
993         linear_texcoord_unnorm(sampler->state->wrap_s, s[j], width,  &x0, &x1, &a);
994         linear_texcoord_unnorm(sampler->state->wrap_t, t[j], height, &y0, &y1, &b);
995         get_texel(sampler, face, level0, x0, y0, 0, tx, 0);
996         get_texel(sampler, face, level0, x1, y0, 0, tx, 1);
997         get_texel(sampler, face, level0, x0, y1, 0, tx, 2);
998         get_texel(sampler, face, level0, x1, y1, 0, tx, 3);
999         if (sampler->state->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
1000            shadow_compare(compare_func, tx, p, 0);
1001            shadow_compare(compare_func, tx, p, 1);
1002            shadow_compare(compare_func, tx, p, 2);
1003            shadow_compare(compare_func, tx, p, 3);
1004         }
1005
1006         for (c = 0; c < 4; c++) {
1007            rgba[c][j] = lerp_2d(a, b, tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
1008         }
1009      }
1010      break;
1011   default:
1012      assert(0);
1013   }
1014}
1015
1016
1017
1018
1019/**
1020 * Called via tgsi_sampler::get_samples()
1021 * Use the sampler's state setting to get a filtered RGBA value
1022 * from the sampler's texture.
1023 *
1024 * XXX we can implement many versions of this function, each
1025 * tightly coded for a specific combination of sampler state
1026 * (nearest + repeat), (bilinear mipmap + clamp), etc.
1027 *
1028 * The update_samplers() function in st_atom_sampler.c could create
1029 * a new tgsi_sampler object for each state combo it finds....
1030 */
1031void
1032sp_get_samples(struct tgsi_sampler *sampler,
1033               const float s[QUAD_SIZE],
1034               const float t[QUAD_SIZE],
1035               const float p[QUAD_SIZE],
1036               float lodbias,
1037               float rgba[NUM_CHANNELS][QUAD_SIZE])
1038{
1039   if (!sampler->texture)
1040      return;
1041
1042   switch (sampler->texture->target) {
1043   case PIPE_TEXTURE_1D:
1044      assert(sampler->state->normalized_coords);
1045      sp_get_samples_1d(sampler, s, t, p, lodbias, rgba);
1046      break;
1047   case PIPE_TEXTURE_2D:
1048      if (sampler->state->normalized_coords)
1049         sp_get_samples_2d(sampler, s, t, p, lodbias, rgba);
1050      else
1051         sp_get_samples_rect(sampler, s, t, p, lodbias, rgba);
1052      break;
1053   case PIPE_TEXTURE_3D:
1054      assert(sampler->state->normalized_coords);
1055      sp_get_samples_3d(sampler, s, t, p, lodbias, rgba);
1056      break;
1057   case PIPE_TEXTURE_CUBE:
1058      assert(sampler->state->normalized_coords);
1059      sp_get_samples_cube(sampler, s, t, p, lodbias, rgba);
1060      break;
1061   default:
1062      assert(0);
1063   }
1064
1065#if 0 /* DEBUG */
1066   {
1067      int i;
1068      printf("Sampled at %f, %f, %f:\n", s[0], t[0], p[0]);
1069      for (i = 0; i < 4; i++) {
1070         printf("Frag %d: %f %f %f %f\n", i,
1071                rgba[0][i],
1072                rgba[1][i],
1073                rgba[2][i],
1074                rgba[3][i]);
1075      }
1076   }
1077#endif
1078}
1079
1080