sp_tex_sample.c revision 38bee46e83b18ff4ad42d340b507b1a15b4326c7
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_texture.h"
39#include "sp_tex_sample.h"
40#include "sp_tile_cache.h"
41#include "pipe/p_context.h"
42#include "pipe/p_defines.h"
43#include "tgsi/tgsi_exec.h"
44#include "util/u_math.h"
45#include "util/u_memory.h"
46
47
48/*
49 * Note, the FRAC macro has to work perfectly.  Otherwise you'll sometimes
50 * see 1-pixel bands of improperly weighted linear-filtered textures.
51 * The tests/texwrap.c demo is a good test.
52 * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
53 * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
54 */
55#define FRAC(f)  ((f) - util_ifloor(f))
56
57
58/**
59 * Linear interpolation macro
60 */
61static INLINE float
62lerp(float a, float v0, float v1)
63{
64   return v0 + a * (v1 - v0);
65}
66
67
68/**
69 * Do 2D/biliner interpolation of float values.
70 * v00, v10, v01 and v11 are typically four texture samples in a square/box.
71 * a and b are the horizontal and vertical interpolants.
72 * It's important that this function is inlined when compiled with
73 * optimization!  If we find that's not true on some systems, convert
74 * to a macro.
75 */
76static INLINE float
77lerp_2d(float a, float b,
78        float v00, float v10, float v01, float v11)
79{
80   const float temp0 = lerp(a, v00, v10);
81   const float temp1 = lerp(a, v01, v11);
82   return lerp(b, temp0, temp1);
83}
84
85
86/**
87 * As above, but 3D interpolation of 8 values.
88 */
89static INLINE float
90lerp_3d(float a, float b, float c,
91        float v000, float v100, float v010, float v110,
92        float v001, float v101, float v011, float v111)
93{
94   const float temp0 = lerp_2d(a, b, v000, v100, v010, v110);
95   const float temp1 = lerp_2d(a, b, v001, v101, v011, v111);
96   return lerp(c, temp0, temp1);
97}
98
99
100
101/**
102 * If A is a signed integer, A % B doesn't give the right value for A < 0
103 * (in terms of texture repeat).  Just casting to unsigned fixes that.
104 */
105#define REMAINDER(A, B) ((unsigned) (A) % (unsigned) (B))
106
107
108/**
109 * Apply texture coord wrapping mode and return integer texture indexes
110 * for a vector of four texcoords (S or T or P).
111 * \param wrapMode  PIPE_TEX_WRAP_x
112 * \param s  the incoming texcoords
113 * \param size  the texture image size
114 * \param icoord  returns the integer texcoords
115 * \return  integer texture index
116 */
117static INLINE void
118nearest_texcoord_4(unsigned wrapMode, const float s[4], unsigned size,
119                   int icoord[4])
120{
121   uint ch;
122   switch (wrapMode) {
123   case PIPE_TEX_WRAP_REPEAT:
124      /* s limited to [0,1) */
125      /* i limited to [0,size-1] */
126      for (ch = 0; ch < 4; ch++) {
127         int i = util_ifloor(s[ch] * size);
128         icoord[ch] = REMAINDER(i, size);
129      }
130      return;
131   case PIPE_TEX_WRAP_CLAMP:
132      /* s limited to [0,1] */
133      /* i limited to [0,size-1] */
134      for (ch = 0; ch < 4; ch++) {
135         if (s[ch] <= 0.0F)
136            icoord[ch] = 0;
137         else if (s[ch] >= 1.0F)
138            icoord[ch] = size - 1;
139         else
140            icoord[ch] = util_ifloor(s[ch] * size);
141      }
142      return;
143   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
144      {
145         /* s limited to [min,max] */
146         /* i limited to [0, size-1] */
147         const float min = 1.0F / (2.0F * size);
148         const float max = 1.0F - min;
149         for (ch = 0; ch < 4; ch++) {
150            if (s[ch] < min)
151               icoord[ch] = 0;
152            else if (s[ch] > max)
153               icoord[ch] = size - 1;
154            else
155               icoord[ch] = util_ifloor(s[ch] * size);
156         }
157      }
158      return;
159   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
160      {
161         /* s limited to [min,max] */
162         /* i limited to [-1, size] */
163         const float min = -1.0F / (2.0F * size);
164         const float max = 1.0F - min;
165         for (ch = 0; ch < 4; ch++) {
166            if (s[ch] <= min)
167               icoord[ch] = -1;
168            else if (s[ch] >= max)
169               icoord[ch] = size;
170            else
171               icoord[ch] = util_ifloor(s[ch] * size);
172         }
173      }
174      return;
175   case PIPE_TEX_WRAP_MIRROR_REPEAT:
176      {
177         const float min = 1.0F / (2.0F * size);
178         const float max = 1.0F - min;
179         for (ch = 0; ch < 4; ch++) {
180            const int flr = util_ifloor(s[ch]);
181            float u;
182            if (flr & 1)
183               u = 1.0F - (s[ch] - (float) flr);
184            else
185               u = s[ch] - (float) flr;
186            if (u < min)
187               icoord[ch] = 0;
188            else if (u > max)
189               icoord[ch] = size - 1;
190            else
191               icoord[ch] = util_ifloor(u * size);
192         }
193      }
194      return;
195   case PIPE_TEX_WRAP_MIRROR_CLAMP:
196      for (ch = 0; ch < 4; ch++) {
197         /* s limited to [0,1] */
198         /* i limited to [0,size-1] */
199         const float u = fabsf(s[ch]);
200         if (u <= 0.0F)
201            icoord[ch] = 0;
202         else if (u >= 1.0F)
203            icoord[ch] = size - 1;
204         else
205            icoord[ch] = util_ifloor(u * size);
206      }
207      return;
208   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
209      {
210         /* s limited to [min,max] */
211         /* i limited to [0, size-1] */
212         const float min = 1.0F / (2.0F * size);
213         const float max = 1.0F - min;
214         for (ch = 0; ch < 4; ch++) {
215            const float u = fabsf(s[ch]);
216            if (u < min)
217               icoord[ch] = 0;
218            else if (u > max)
219               icoord[ch] = size - 1;
220            else
221               icoord[ch] = util_ifloor(u * size);
222         }
223      }
224      return;
225   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
226      {
227         /* s limited to [min,max] */
228         /* i limited to [0, size-1] */
229         const float min = -1.0F / (2.0F * size);
230         const float max = 1.0F - min;
231         for (ch = 0; ch < 4; ch++) {
232            const float u = fabsf(s[ch]);
233            if (u < min)
234               icoord[ch] = -1;
235            else if (u > max)
236               icoord[ch] = size;
237            else
238               icoord[ch] = util_ifloor(u * size);
239         }
240      }
241      return;
242   default:
243      assert(0);
244   }
245}
246
247
248/**
249 * Used to compute texel locations for linear sampling for four texcoords.
250 * \param wrapMode  PIPE_TEX_WRAP_x
251 * \param s  the texcoords
252 * \param size  the texture image size
253 * \param icoord0  returns first texture indexes
254 * \param icoord1  returns second texture indexes (usually icoord0 + 1)
255 * \param w  returns blend factor/weight between texture indexes
256 * \param icoord  returns the computed integer texture coords
257 */
258static INLINE void
259linear_texcoord_4(unsigned wrapMode, const float s[4], unsigned size,
260                  int icoord0[4], int icoord1[4], float w[4])
261{
262   uint ch;
263
264   switch (wrapMode) {
265   case PIPE_TEX_WRAP_REPEAT:
266      for (ch = 0; ch < 4; ch++) {
267         float u = s[ch] * size - 0.5F;
268         icoord0[ch] = REMAINDER(util_ifloor(u), size);
269         icoord1[ch] = REMAINDER(icoord0[ch] + 1, size);
270         w[ch] = FRAC(u);
271      }
272      break;;
273   case PIPE_TEX_WRAP_CLAMP:
274      for (ch = 0; ch < 4; ch++) {
275         float u = CLAMP(s[ch], 0.0F, 1.0F);
276         u = u * size - 0.5f;
277         icoord0[ch] = util_ifloor(u);
278         icoord1[ch] = icoord0[ch] + 1;
279         w[ch] = FRAC(u);
280      }
281      break;;
282   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
283      for (ch = 0; ch < 4; ch++) {
284         float u = CLAMP(s[ch], 0.0F, 1.0F);
285         u = u * size - 0.5f;
286         icoord0[ch] = util_ifloor(u);
287         icoord1[ch] = icoord0[ch] + 1;
288         if (icoord0[ch] < 0)
289            icoord0[ch] = 0;
290         if (icoord1[ch] >= (int) size)
291            icoord1[ch] = size - 1;
292         w[ch] = FRAC(u);
293      }
294      break;;
295   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
296      {
297         const float min = -1.0F / (2.0F * size);
298         const float max = 1.0F - min;
299         for (ch = 0; ch < 4; ch++) {
300            float u = CLAMP(s[ch], min, max);
301            u = u * size - 0.5f;
302            icoord0[ch] = util_ifloor(u);
303            icoord1[ch] = icoord0[ch] + 1;
304            w[ch] = FRAC(u);
305         }
306      }
307      break;;
308   case PIPE_TEX_WRAP_MIRROR_REPEAT:
309      for (ch = 0; ch < 4; ch++) {
310         const int flr = util_ifloor(s[ch]);
311         float u;
312         if (flr & 1)
313            u = 1.0F - (s[ch] - (float) flr);
314         else
315            u = s[ch] - (float) flr;
316         u = u * size - 0.5F;
317         icoord0[ch] = util_ifloor(u);
318         icoord1[ch] = icoord0[ch] + 1;
319         if (icoord0[ch] < 0)
320            icoord0[ch] = 0;
321         if (icoord1[ch] >= (int) size)
322            icoord1[ch] = size - 1;
323         w[ch] = FRAC(u);
324      }
325      break;;
326   case PIPE_TEX_WRAP_MIRROR_CLAMP:
327      for (ch = 0; ch < 4; ch++) {
328         float u = fabsf(s[ch]);
329         if (u >= 1.0F)
330            u = (float) size;
331         else
332            u *= size;
333         u -= 0.5F;
334         icoord0[ch] = util_ifloor(u);
335         icoord1[ch] = icoord0[ch] + 1;
336         w[ch] = FRAC(u);
337      }
338      break;;
339   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
340      for (ch = 0; ch < 4; ch++) {
341         float u = fabsf(s[ch]);
342         if (u >= 1.0F)
343            u = (float) size;
344         else
345            u *= size;
346         u -= 0.5F;
347         icoord0[ch] = util_ifloor(u);
348         icoord1[ch] = icoord0[ch] + 1;
349         if (icoord0[ch] < 0)
350            icoord0[ch] = 0;
351         if (icoord1[ch] >= (int) size)
352            icoord1[ch] = size - 1;
353         w[ch] = FRAC(u);
354      }
355      break;;
356   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
357      {
358         const float min = -1.0F / (2.0F * size);
359         const float max = 1.0F - min;
360         for (ch = 0; ch < 4; ch++) {
361            float u = fabsf(s[ch]);
362            if (u <= min)
363               u = min * size;
364            else if (u >= max)
365               u = max * size;
366            else
367               u *= size;
368            u -= 0.5F;
369            icoord0[ch] = util_ifloor(u);
370            icoord1[ch] = icoord0[ch] + 1;
371            w[ch] = FRAC(u);
372         }
373      }
374      break;;
375   default:
376      assert(0);
377   }
378}
379
380
381/**
382 * For RECT textures / unnormalized texcoords
383 * Only a subset of wrap modes supported.
384 */
385static INLINE void
386nearest_texcoord_unnorm_4(unsigned wrapMode, const float s[4], unsigned size,
387                          int icoord[4])
388{
389   uint ch;
390   switch (wrapMode) {
391   case PIPE_TEX_WRAP_CLAMP:
392      for (ch = 0; ch < 4; ch++) {
393         int i = util_ifloor(s[ch]);
394         icoord[ch]= CLAMP(i, 0, (int) size-1);
395      }
396      return;
397   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
398      /* fall-through */
399   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
400      for (ch = 0; ch < 4; ch++) {
401         icoord[ch]= util_ifloor( CLAMP(s[ch], 0.5F, (float) size - 0.5F) );
402      }
403      return;
404   default:
405      assert(0);
406   }
407}
408
409
410/**
411 * For RECT textures / unnormalized texcoords.
412 * Only a subset of wrap modes supported.
413 */
414static INLINE void
415linear_texcoord_unnorm_4(unsigned wrapMode, const float s[4], unsigned size,
416                         int icoord0[4], int icoord1[4], float w[4])
417{
418   uint ch;
419   switch (wrapMode) {
420   case PIPE_TEX_WRAP_CLAMP:
421      for (ch = 0; ch < 4; ch++) {
422         /* Not exactly what the spec says, but it matches NVIDIA output */
423         float u = CLAMP(s[ch] - 0.5F, 0.0f, (float) size - 1.0f);
424         icoord0[ch] = util_ifloor(u);
425         icoord1[ch] = icoord0[ch] + 1;
426         w[ch] = FRAC(u);
427      }
428      return;
429   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
430      /* fall-through */
431   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
432      for (ch = 0; ch < 4; ch++) {
433         float u = CLAMP(s[ch], 0.5F, (float) size - 0.5F);
434         u -= 0.5F;
435         icoord0[ch] = util_ifloor(u);
436         icoord1[ch] = icoord0[ch] + 1;
437         if (icoord1[ch] > (int) size - 1)
438            icoord1[ch] = size - 1;
439         w[ch] = FRAC(u);
440      }
441      break;
442   default:
443      assert(0);
444   }
445}
446
447
448static unsigned
449choose_cube_face(float rx, float ry, float rz, float *newS, float *newT)
450{
451   /*
452      major axis
453      direction     target                             sc     tc    ma
454      ----------    -------------------------------    ---    ---   ---
455       +rx          TEXTURE_CUBE_MAP_POSITIVE_X_EXT    -rz    -ry   rx
456       -rx          TEXTURE_CUBE_MAP_NEGATIVE_X_EXT    +rz    -ry   rx
457       +ry          TEXTURE_CUBE_MAP_POSITIVE_Y_EXT    +rx    +rz   ry
458       -ry          TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT    +rx    -rz   ry
459       +rz          TEXTURE_CUBE_MAP_POSITIVE_Z_EXT    +rx    -ry   rz
460       -rz          TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT    -rx    -ry   rz
461   */
462   const float arx = fabsf(rx), ary = fabsf(ry), arz = fabsf(rz);
463   unsigned face;
464   float sc, tc, ma;
465
466   if (arx > ary && arx > arz) {
467      if (rx >= 0.0F) {
468         face = PIPE_TEX_FACE_POS_X;
469         sc = -rz;
470         tc = -ry;
471         ma = arx;
472      }
473      else {
474         face = PIPE_TEX_FACE_NEG_X;
475         sc = rz;
476         tc = -ry;
477         ma = arx;
478      }
479   }
480   else if (ary > arx && ary > arz) {
481      if (ry >= 0.0F) {
482         face = PIPE_TEX_FACE_POS_Y;
483         sc = rx;
484         tc = rz;
485         ma = ary;
486      }
487      else {
488         face = PIPE_TEX_FACE_NEG_Y;
489         sc = rx;
490         tc = -rz;
491         ma = ary;
492      }
493   }
494   else {
495      if (rz > 0.0F) {
496         face = PIPE_TEX_FACE_POS_Z;
497         sc = rx;
498         tc = -ry;
499         ma = arz;
500      }
501      else {
502         face = PIPE_TEX_FACE_NEG_Z;
503         sc = -rx;
504         tc = -ry;
505         ma = arz;
506      }
507   }
508
509   *newS = ( sc / ma + 1.0F ) * 0.5F;
510   *newT = ( tc / ma + 1.0F ) * 0.5F;
511
512   return face;
513}
514
515
516/**
517 * Examine the quad's texture coordinates to compute the partial
518 * derivatives w.r.t X and Y, then compute lambda (level of detail).
519 *
520 * This is only done for fragment shaders, not vertex shaders.
521 */
522static float
523compute_lambda(const struct pipe_texture *tex,
524               const struct pipe_sampler_state *sampler,
525               const float s[QUAD_SIZE],
526               const float t[QUAD_SIZE],
527               const float p[QUAD_SIZE],
528               float lodbias)
529{
530   float rho, lambda;
531
532   assert(sampler->normalized_coords);
533
534   assert(s);
535   {
536      float dsdx = s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT];
537      float dsdy = s[QUAD_TOP_LEFT]     - s[QUAD_BOTTOM_LEFT];
538      dsdx = fabsf(dsdx);
539      dsdy = fabsf(dsdy);
540      rho = MAX2(dsdx, dsdy) * tex->width[0];
541   }
542   if (t) {
543      float dtdx = t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT];
544      float dtdy = t[QUAD_TOP_LEFT]     - t[QUAD_BOTTOM_LEFT];
545      float max;
546      dtdx = fabsf(dtdx);
547      dtdy = fabsf(dtdy);
548      max = MAX2(dtdx, dtdy) * tex->height[0];
549      rho = MAX2(rho, max);
550   }
551   if (p) {
552      float dpdx = p[QUAD_BOTTOM_RIGHT] - p[QUAD_BOTTOM_LEFT];
553      float dpdy = p[QUAD_TOP_LEFT]     - p[QUAD_BOTTOM_LEFT];
554      float max;
555      dpdx = fabsf(dpdx);
556      dpdy = fabsf(dpdy);
557      max = MAX2(dpdx, dpdy) * tex->depth[0];
558      rho = MAX2(rho, max);
559   }
560
561   lambda = util_fast_log2(rho);
562   lambda += lodbias + sampler->lod_bias;
563   lambda = CLAMP(lambda, sampler->min_lod, sampler->max_lod);
564
565   return lambda;
566}
567
568
569/**
570 * Do several things here:
571 * 1. Compute lambda from the texcoords, if needed
572 * 2. Determine if we're minifying or magnifying
573 * 3. If minifying, choose mipmap levels
574 * 4. Return image filter to use within mipmap images
575 * \param level0  Returns first mipmap level to sample from
576 * \param level1  Returns second mipmap level to sample from
577 * \param levelBlend  Returns blend factor between levels, in [0,1]
578 * \param imgFilter  Returns either the min or mag filter, depending on lambda
579 */
580static void
581choose_mipmap_levels(const struct pipe_texture *texture,
582                     const struct pipe_sampler_state *sampler,
583                     const float s[QUAD_SIZE],
584                     const float t[QUAD_SIZE],
585                     const float p[QUAD_SIZE],
586                     float lodbias,
587                     unsigned *level0, unsigned *level1, float *levelBlend,
588                     unsigned *imgFilter)
589{
590   if (sampler->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) {
591      /* no mipmap selection needed */
592      *level0 = *level1 = CLAMP((int) sampler->min_lod,
593                                0, (int) texture->last_level);
594
595      if (sampler->min_img_filter != sampler->mag_img_filter) {
596         /* non-mipmapped texture, but still need to determine if doing
597          * minification or magnification.
598          */
599         float lambda = compute_lambda(texture, sampler, s, t, p, lodbias);
600         if (lambda <= 0.0) {
601            *imgFilter = sampler->mag_img_filter;
602         }
603         else {
604            *imgFilter = sampler->min_img_filter;
605         }
606      }
607      else {
608         *imgFilter = sampler->mag_img_filter;
609      }
610   }
611   else {
612      float lambda;
613
614      if (1)
615         /* fragment shader */
616         lambda = compute_lambda(texture, sampler, s, t, p, lodbias);
617      else
618         /* vertex shader */
619         lambda = lodbias; /* not really a bias, but absolute LOD */
620
621      if (lambda <= 0.0) { /* XXX threshold depends on the filter */
622         /* magnifying */
623         *imgFilter = sampler->mag_img_filter;
624         *level0 = *level1 = 0;
625      }
626      else {
627         /* minifying */
628         *imgFilter = sampler->min_img_filter;
629
630         /* choose mipmap level(s) and compute the blend factor between them */
631         if (sampler->min_mip_filter == PIPE_TEX_MIPFILTER_NEAREST) {
632            /* Nearest mipmap level */
633            const int lvl = (int) (lambda + 0.5);
634            *level0 =
635            *level1 = CLAMP(lvl, 0, (int) texture->last_level);
636         }
637         else {
638            /* Linear interpolation between mipmap levels */
639            const int lvl = (int) lambda;
640            *level0 = CLAMP(lvl,     0, (int) texture->last_level);
641            *level1 = CLAMP(lvl + 1, 0, (int) texture->last_level);
642            *levelBlend = FRAC(lambda);  /* blending weight between levels */
643         }
644      }
645   }
646}
647
648
649/**
650 * Get a texel from a texture, using the texture tile cache.
651 *
652 * \param face  the cube face in 0..5
653 * \param level  the mipmap level
654 * \param x  the x coord of texel within 2D image
655 * \param y  the y coord of texel within 2D image
656 * \param z  which slice of a 3D texture
657 * \param rgba  the quad to put the texel/color into
658 * \param j  which element of the rgba quad to write to
659 *
660 * XXX maybe move this into sp_tile_cache.c and merge with the
661 * sp_get_cached_tile_tex() function.  Also, get 4 texels instead of 1...
662 */
663static void
664get_texel(const struct tgsi_sampler *tgsi_sampler,
665          unsigned face, unsigned level, int x, int y, int z,
666          float rgba[NUM_CHANNELS][QUAD_SIZE], unsigned j)
667{
668   const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
669   const struct softpipe_context *sp = samp->sp;
670   const uint unit = samp->unit;
671   const struct pipe_texture *texture = sp->texture[unit];
672   const struct pipe_sampler_state *sampler = sp->sampler[unit];
673
674   if (x < 0 || x >= (int) texture->width[level] ||
675       y < 0 || y >= (int) texture->height[level] ||
676       z < 0 || z >= (int) texture->depth[level]) {
677      rgba[0][j] = sampler->border_color[0];
678      rgba[1][j] = sampler->border_color[1];
679      rgba[2][j] = sampler->border_color[2];
680      rgba[3][j] = sampler->border_color[3];
681   }
682   else {
683      const int tx = x % TILE_SIZE;
684      const int ty = y % TILE_SIZE;
685      const struct softpipe_cached_tile *tile
686         = sp_get_cached_tile_tex(samp->sp, samp->cache,
687                                  x, y, z, face, level);
688      rgba[0][j] = tile->data.color[ty][tx][0];
689      rgba[1][j] = tile->data.color[ty][tx][1];
690      rgba[2][j] = tile->data.color[ty][tx][2];
691      rgba[3][j] = tile->data.color[ty][tx][3];
692      if (0)
693      {
694         debug_printf("Get texel %f %f %f %f from %s\n",
695                      rgba[0][j], rgba[1][j], rgba[2][j], rgba[3][j],
696                      pf_name(texture->format));
697      }
698   }
699}
700
701
702/**
703 * Compare texcoord 'p' (aka R) against texture value 'rgba[0]'
704 * When we sampled the depth texture, the depth value was put into all
705 * RGBA channels.  We look at the red channel here.
706 */
707static INLINE void
708shadow_compare(uint compare_func,
709               float rgba[NUM_CHANNELS][QUAD_SIZE],
710               const float p[QUAD_SIZE],
711               uint j)
712{
713   int k;
714   switch (compare_func) {
715   case PIPE_FUNC_LESS:
716      k = p[j] < rgba[0][j];
717      break;
718   case PIPE_FUNC_LEQUAL:
719      k = p[j] <= rgba[0][j];
720      break;
721   case PIPE_FUNC_GREATER:
722      k = p[j] > rgba[0][j];
723      break;
724   case PIPE_FUNC_GEQUAL:
725      k = p[j] >= rgba[0][j];
726      break;
727   case PIPE_FUNC_EQUAL:
728      k = p[j] == rgba[0][j];
729      break;
730   case PIPE_FUNC_NOTEQUAL:
731      k = p[j] != rgba[0][j];
732      break;
733   case PIPE_FUNC_ALWAYS:
734      k = 1;
735      break;
736   case PIPE_FUNC_NEVER:
737      k = 0;
738      break;
739   default:
740      k = 0;
741      assert(0);
742      break;
743   }
744
745   rgba[0][j] = rgba[1][j] = rgba[2][j] = (float) k;
746}
747
748
749/**
750 * Common code for sampling 1D/2D/cube textures.
751 * Could probably extend for 3D...
752 */
753static void
754sp_get_samples_2d_common(const struct tgsi_sampler *tgsi_sampler,
755                         const float s[QUAD_SIZE],
756                         const float t[QUAD_SIZE],
757                         const float p[QUAD_SIZE],
758                         float lodbias,
759                         float rgba[NUM_CHANNELS][QUAD_SIZE],
760                         const unsigned faces[4])
761{
762   const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
763   const struct softpipe_context *sp = samp->sp;
764   const uint unit = samp->unit;
765   const struct pipe_texture *texture = sp->texture[unit];
766   const struct pipe_sampler_state *sampler = sp->sampler[unit];
767   const uint compare_func = sampler->compare_func;
768   unsigned level0, level1, j, imgFilter;
769   int width, height;
770   float levelBlend;
771
772   choose_mipmap_levels(texture, sampler, s, t, p, lodbias,
773                        &level0, &level1, &levelBlend, &imgFilter);
774
775   assert(sampler->normalized_coords);
776
777   width = texture->width[level0];
778   height = texture->height[level0];
779
780   assert(width > 0);
781
782   switch (imgFilter) {
783   case PIPE_TEX_FILTER_NEAREST:
784      {
785         int x[4], y[4];
786         nearest_texcoord_4(sampler->wrap_s, s, width, x);
787         nearest_texcoord_4(sampler->wrap_t, t, height, y);
788
789         for (j = 0; j < QUAD_SIZE; j++) {
790            get_texel(tgsi_sampler, faces[j], level0, x[j], y[j], 0, rgba, j);
791            if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
792               shadow_compare(compare_func, rgba, p, j);
793            }
794
795            if (level0 != level1) {
796               /* get texels from second mipmap level and blend */
797               float rgba2[4][4];
798               unsigned c;
799               x[j] /= 2;
800               y[j] /= 2;
801               get_texel(tgsi_sampler, faces[j], level1, x[j], y[j], 0,
802                         rgba2, j);
803               if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
804                  shadow_compare(compare_func, rgba2, p, j);
805               }
806
807               for (c = 0; c < NUM_CHANNELS; c++) {
808                  rgba[c][j] = lerp(levelBlend, rgba[c][j], rgba2[c][j]);
809               }
810            }
811         }
812      }
813      break;
814   case PIPE_TEX_FILTER_LINEAR:
815   case PIPE_TEX_FILTER_ANISO:
816      {
817         int x0[4], y0[4], x1[4], y1[4];
818         float xw[4], yw[4]; /* weights */
819
820         linear_texcoord_4(sampler->wrap_s, s, width, x0, x1, xw);
821         linear_texcoord_4(sampler->wrap_t, t, height, y0, y1, yw);
822
823         for (j = 0; j < QUAD_SIZE; j++) {
824            float tx[4][4]; /* texels */
825            int c;
826            get_texel(tgsi_sampler, faces[j], level0, x0[j], y0[j], 0, tx, 0);
827            get_texel(tgsi_sampler, faces[j], level0, x1[j], y0[j], 0, tx, 1);
828            get_texel(tgsi_sampler, faces[j], level0, x0[j], y1[j], 0, tx, 2);
829            get_texel(tgsi_sampler, faces[j], level0, x1[j], y1[j], 0, tx, 3);
830            if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
831               shadow_compare(compare_func, tx, p, 0);
832               shadow_compare(compare_func, tx, p, 1);
833               shadow_compare(compare_func, tx, p, 2);
834               shadow_compare(compare_func, tx, p, 3);
835            }
836
837            /* interpolate R, G, B, A */
838            for (c = 0; c < 4; c++) {
839               rgba[c][j] = lerp_2d(xw[j], yw[j],
840                                    tx[c][0], tx[c][1],
841                                    tx[c][2], tx[c][3]);
842            }
843
844            if (level0 != level1) {
845               /* get texels from second mipmap level and blend */
846               float rgba2[4][4];
847               x0[j] /= 2;
848               y0[j] /= 2;
849               x1[j] /= 2;
850               y1[j] /= 2;
851               get_texel(tgsi_sampler, faces[j], level1, x0[j], y0[j], 0, tx, 0);
852               get_texel(tgsi_sampler, faces[j], level1, x1[j], y0[j], 0, tx, 1);
853               get_texel(tgsi_sampler, faces[j], level1, x0[j], y1[j], 0, tx, 2);
854               get_texel(tgsi_sampler, faces[j], level1, x1[j], y1[j], 0, tx, 3);
855               if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){
856                  shadow_compare(compare_func, tx, p, 0);
857                  shadow_compare(compare_func, tx, p, 1);
858                  shadow_compare(compare_func, tx, p, 2);
859                  shadow_compare(compare_func, tx, p, 3);
860               }
861
862               /* interpolate R, G, B, A */
863               for (c = 0; c < 4; c++) {
864                  rgba2[c][j] = lerp_2d(xw[j], yw[j],
865                                        tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
866               }
867
868               for (c = 0; c < NUM_CHANNELS; c++) {
869                  rgba[c][j] = lerp(levelBlend, rgba[c][j], rgba2[c][j]);
870               }
871            }
872         }
873      }
874      break;
875   default:
876      assert(0);
877   }
878}
879
880
881static INLINE void
882sp_get_samples_1d(const struct tgsi_sampler *sampler,
883                  const float s[QUAD_SIZE],
884                  const float t[QUAD_SIZE],
885                  const float p[QUAD_SIZE],
886                  float lodbias,
887                  float rgba[NUM_CHANNELS][QUAD_SIZE])
888{
889   static const unsigned faces[4] = {0, 0, 0, 0};
890   static const float tzero[4] = {0, 0, 0, 0};
891   sp_get_samples_2d_common(sampler, s, tzero, NULL, lodbias, rgba, faces);
892}
893
894
895static INLINE void
896sp_get_samples_2d(const struct tgsi_sampler *sampler,
897                  const float s[QUAD_SIZE],
898                  const float t[QUAD_SIZE],
899                  const float p[QUAD_SIZE],
900                  float lodbias,
901                  float rgba[NUM_CHANNELS][QUAD_SIZE])
902{
903   static const unsigned faces[4] = {0, 0, 0, 0};
904   sp_get_samples_2d_common(sampler, s, t, p, lodbias, rgba, faces);
905}
906
907
908static INLINE void
909sp_get_samples_3d(const struct tgsi_sampler *tgsi_sampler,
910                  const float s[QUAD_SIZE],
911                  const float t[QUAD_SIZE],
912                  const float p[QUAD_SIZE],
913                  float lodbias,
914                  float rgba[NUM_CHANNELS][QUAD_SIZE])
915{
916   const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
917   const struct softpipe_context *sp = samp->sp;
918   const uint unit = samp->unit;
919   const struct pipe_texture *texture = sp->texture[unit];
920   const struct pipe_sampler_state *sampler = sp->sampler[unit];
921   /* get/map pipe_surfaces corresponding to 3D tex slices */
922   unsigned level0, level1, j, imgFilter;
923   int width, height, depth;
924   float levelBlend;
925   const uint face = 0;
926
927   choose_mipmap_levels(texture, sampler, s, t, p, lodbias,
928                        &level0, &level1, &levelBlend, &imgFilter);
929
930   assert(sampler->normalized_coords);
931
932   width = texture->width[level0];
933   height = texture->height[level0];
934   depth = texture->depth[level0];
935
936   assert(width > 0);
937   assert(height > 0);
938   assert(depth > 0);
939
940   switch (imgFilter) {
941   case PIPE_TEX_FILTER_NEAREST:
942      {
943         int x[4], y[4], z[4];
944         nearest_texcoord_4(sampler->wrap_s, s, width, x);
945         nearest_texcoord_4(sampler->wrap_t, t, height, y);
946         nearest_texcoord_4(sampler->wrap_r, p, depth, z);
947         for (j = 0; j < QUAD_SIZE; j++) {
948            get_texel(tgsi_sampler, face, level0, x[j], y[j], z[j], rgba, j);
949            if (level0 != level1) {
950               /* get texels from second mipmap level and blend */
951               float rgba2[4][4];
952               unsigned c;
953               x[j] /= 2;
954               y[j] /= 2;
955               z[j] /= 2;
956               get_texel(tgsi_sampler, face, level1, x[j], y[j], z[j], rgba2, j);
957               for (c = 0; c < NUM_CHANNELS; c++) {
958                  rgba[c][j] = lerp(levelBlend, rgba2[c][j], rgba[c][j]);
959               }
960            }
961         }
962      }
963      break;
964   case PIPE_TEX_FILTER_LINEAR:
965   case PIPE_TEX_FILTER_ANISO:
966      {
967         int x0[4], x1[4], y0[4], y1[4], z0[4], z1[4];
968         float xw[4], yw[4], zw[4]; /* interpolation weights */
969         linear_texcoord_4(sampler->wrap_s, s, width,  x0, x1, xw);
970         linear_texcoord_4(sampler->wrap_t, t, height, y0, y1, yw);
971         linear_texcoord_4(sampler->wrap_r, p, depth,  z0, z1, zw);
972
973         for (j = 0; j < QUAD_SIZE; j++) {
974            int c;
975            float tx0[4][4], tx1[4][4];
976            get_texel(tgsi_sampler, face, level0, x0[j], y0[j], z0[j], tx0, 0);
977            get_texel(tgsi_sampler, face, level0, x1[j], y0[j], z0[j], tx0, 1);
978            get_texel(tgsi_sampler, face, level0, x0[j], y1[j], z0[j], tx0, 2);
979            get_texel(tgsi_sampler, face, level0, x1[j], y1[j], z0[j], tx0, 3);
980            get_texel(tgsi_sampler, face, level0, x0[j], y0[j], z1[j], tx1, 0);
981            get_texel(tgsi_sampler, face, level0, x1[j], y0[j], z1[j], tx1, 1);
982            get_texel(tgsi_sampler, face, level0, x0[j], y1[j], z1[j], tx1, 2);
983            get_texel(tgsi_sampler, face, level0, x1[j], y1[j], z1[j], tx1, 3);
984
985            /* interpolate R, G, B, A */
986            for (c = 0; c < 4; c++) {
987               rgba[c][j] = lerp_3d(xw[j], yw[j], zw[j],
988                                    tx0[c][0], tx0[c][1],
989                                    tx0[c][2], tx0[c][3],
990                                    tx1[c][0], tx1[c][1],
991                                    tx1[c][2], tx1[c][3]);
992            }
993
994            if (level0 != level1) {
995               /* get texels from second mipmap level and blend */
996               float rgba2[4][4];
997               x0[j] /= 2;
998               y0[j] /= 2;
999               z0[j] /= 2;
1000               x1[j] /= 2;
1001               y1[j] /= 2;
1002               z1[j] /= 2;
1003               get_texel(tgsi_sampler, face, level1, x0[j], y0[j], z0[j], tx0, 0);
1004               get_texel(tgsi_sampler, face, level1, x1[j], y0[j], z0[j], tx0, 1);
1005               get_texel(tgsi_sampler, face, level1, x0[j], y1[j], z0[j], tx0, 2);
1006               get_texel(tgsi_sampler, face, level1, x1[j], y1[j], z0[j], tx0, 3);
1007               get_texel(tgsi_sampler, face, level1, x0[j], y0[j], z1[j], tx1, 0);
1008               get_texel(tgsi_sampler, face, level1, x1[j], y0[j], z1[j], tx1, 1);
1009               get_texel(tgsi_sampler, face, level1, x0[j], y1[j], z1[j], tx1, 2);
1010               get_texel(tgsi_sampler, face, level1, x1[j], y1[j], z1[j], tx1, 3);
1011
1012               /* interpolate R, G, B, A */
1013               for (c = 0; c < 4; c++) {
1014                  rgba2[c][j] = lerp_3d(xw[j], yw[j], zw[j],
1015                                        tx0[c][0], tx0[c][1],
1016                                        tx0[c][2], tx0[c][3],
1017                                        tx1[c][0], tx1[c][1],
1018                                        tx1[c][2], tx1[c][3]);
1019               }
1020
1021               /* blend mipmap levels */
1022               for (c = 0; c < NUM_CHANNELS; c++) {
1023                  rgba[c][j] = lerp(levelBlend, rgba[c][j], rgba2[c][j]);
1024               }
1025            }
1026         }
1027      }
1028      break;
1029   default:
1030      assert(0);
1031   }
1032}
1033
1034
1035static void
1036sp_get_samples_cube(const struct tgsi_sampler *sampler,
1037                    const float s[QUAD_SIZE],
1038                    const float t[QUAD_SIZE],
1039                    const float p[QUAD_SIZE],
1040                    float lodbias,
1041                    float rgba[NUM_CHANNELS][QUAD_SIZE])
1042{
1043   unsigned faces[QUAD_SIZE], j;
1044   float ssss[4], tttt[4];
1045   for (j = 0; j < QUAD_SIZE; j++) {
1046      faces[j] = choose_cube_face(s[j], t[j], p[j], ssss + j, tttt + j);
1047   }
1048   sp_get_samples_2d_common(sampler, ssss, tttt, NULL, lodbias, rgba, faces);
1049}
1050
1051
1052static void
1053sp_get_samples_rect(const struct tgsi_sampler *tgsi_sampler,
1054                    const float s[QUAD_SIZE],
1055                    const float t[QUAD_SIZE],
1056                    const float p[QUAD_SIZE],
1057                    float lodbias,
1058                    float rgba[NUM_CHANNELS][QUAD_SIZE])
1059{
1060   const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
1061   const struct softpipe_context *sp = samp->sp;
1062   const uint unit = samp->unit;
1063   const struct pipe_texture *texture = sp->texture[unit];
1064   const struct pipe_sampler_state *sampler = sp->sampler[unit];
1065   //sp_get_samples_2d_common(sampler, s, t, p, lodbias, rgba, faces);
1066   static const uint face = 0;
1067   const uint compare_func = sampler->compare_func;
1068   unsigned level0, level1, j, imgFilter;
1069   int width, height;
1070   float levelBlend;
1071
1072   choose_mipmap_levels(texture, sampler, s, t, p, lodbias,
1073                        &level0, &level1, &levelBlend, &imgFilter);
1074
1075   /* texture RECTS cannot be mipmapped */
1076   assert(level0 == level1);
1077
1078   width = texture->width[level0];
1079   height = texture->height[level0];
1080
1081   assert(width > 0);
1082
1083   switch (imgFilter) {
1084   case PIPE_TEX_FILTER_NEAREST:
1085      {
1086         int x[4], y[4];
1087         nearest_texcoord_unnorm_4(sampler->wrap_s, s, width, x);
1088         nearest_texcoord_unnorm_4(sampler->wrap_t, t, height, y);
1089         for (j = 0; j < QUAD_SIZE; j++) {
1090            get_texel(tgsi_sampler, face, level0, x[j], y[j], 0, rgba, j);
1091            if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
1092               shadow_compare(compare_func, rgba, p, j);
1093            }
1094         }
1095      }
1096      break;
1097   case PIPE_TEX_FILTER_LINEAR:
1098   case PIPE_TEX_FILTER_ANISO:
1099      {
1100         int x0[4], y0[4], x1[4], y1[4];
1101         float xw[4], yw[4]; /* weights */
1102         linear_texcoord_unnorm_4(sampler->wrap_s, s, width,  x0, x1, xw);
1103         linear_texcoord_unnorm_4(sampler->wrap_t, t, height, y0, y1, yw);
1104         for (j = 0; j < QUAD_SIZE; j++) {
1105            float tx[4][4]; /* texels */
1106            int c;
1107            get_texel(tgsi_sampler, face, level0, x0[j], y0[j], 0, tx, 0);
1108            get_texel(tgsi_sampler, face, level0, x1[j], y0[j], 0, tx, 1);
1109            get_texel(tgsi_sampler, face, level0, x0[j], y1[j], 0, tx, 2);
1110            get_texel(tgsi_sampler, face, level0, x1[j], y1[j], 0, tx, 3);
1111            if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) {
1112               shadow_compare(compare_func, tx, p, 0);
1113               shadow_compare(compare_func, tx, p, 1);
1114               shadow_compare(compare_func, tx, p, 2);
1115               shadow_compare(compare_func, tx, p, 3);
1116            }
1117            for (c = 0; c < 4; c++) {
1118               rgba[c][j] = lerp_2d(xw[j], yw[j],
1119                                    tx[c][0], tx[c][1], tx[c][2], tx[c][3]);
1120            }
1121         }
1122      }
1123      break;
1124   default:
1125      assert(0);
1126   }
1127}
1128
1129
1130/**
1131 * Called via tgsi_sampler::get_samples()
1132 * Use the sampler's state setting to get a filtered RGBA value
1133 * from the sampler's texture.
1134 *
1135 * XXX we can implement many versions of this function, each
1136 * tightly coded for a specific combination of sampler state
1137 * (nearest + repeat), (bilinear mipmap + clamp), etc.
1138 *
1139 * The update_samplers() function in st_atom_sampler.c could create
1140 * a new tgsi_sampler object for each state combo it finds....
1141 */
1142void
1143sp_get_samples(struct tgsi_sampler *tgsi_sampler,
1144               const float s[QUAD_SIZE],
1145               const float t[QUAD_SIZE],
1146               const float p[QUAD_SIZE],
1147               float lodbias,
1148               float rgba[NUM_CHANNELS][QUAD_SIZE])
1149{
1150   const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
1151   const struct softpipe_context *sp = samp->sp;
1152   const uint unit = samp->unit;
1153   const struct pipe_texture *texture = sp->texture[unit];
1154   const struct pipe_sampler_state *sampler = sp->sampler[unit];
1155
1156   if (!texture)
1157      return;
1158
1159   switch (texture->target) {
1160   case PIPE_TEXTURE_1D:
1161      assert(sampler->normalized_coords);
1162      sp_get_samples_1d(tgsi_sampler, s, t, p, lodbias, rgba);
1163      break;
1164   case PIPE_TEXTURE_2D:
1165      if (sampler->normalized_coords)
1166         sp_get_samples_2d(tgsi_sampler, s, t, p, lodbias, rgba);
1167      else
1168         sp_get_samples_rect(tgsi_sampler, s, t, p, lodbias, rgba);
1169      break;
1170   case PIPE_TEXTURE_3D:
1171      assert(sampler->normalized_coords);
1172      sp_get_samples_3d(tgsi_sampler, s, t, p, lodbias, rgba);
1173      break;
1174   case PIPE_TEXTURE_CUBE:
1175      assert(sampler->normalized_coords);
1176      sp_get_samples_cube(tgsi_sampler, s, t, p, lodbias, rgba);
1177      break;
1178   default:
1179      assert(0);
1180   }
1181
1182#if 0 /* DEBUG */
1183   {
1184      int i;
1185      printf("Sampled at %f, %f, %f:\n", s[0], t[0], p[0]);
1186      for (i = 0; i < 4; i++) {
1187         printf("Frag %d: %f %f %f %f\n", i,
1188                rgba[0][i],
1189                rgba[1][i],
1190                rgba[2][i],
1191                rgba[3][i]);
1192      }
1193   }
1194#endif
1195}
1196
1197