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