• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2007 VMware, Inc.
4  * All Rights Reserved.
5  * Copyright 2008-2010 VMware, Inc.  All rights reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sub license, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial portions
17  * of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  **************************************************************************/
28 
29 /**
30  * Texture sampling
31  *
32  * Authors:
33  *   Brian Paul
34  *   Keith Whitwell
35  */
36 
37 #include "pipe/p_context.h"
38 #include "pipe/p_defines.h"
39 #include "pipe/p_shader_tokens.h"
40 #include "util/u_math.h"
41 #include "util/u_format.h"
42 #include "util/u_memory.h"
43 #include "util/u_inlines.h"
44 #include "sp_quad.h"   /* only for #define QUAD_* tokens */
45 #include "sp_tex_sample.h"
46 #include "sp_texture.h"
47 #include "sp_tex_tile_cache.h"
48 
49 
50 /** Set to one to help debug texture sampling */
51 #define DEBUG_TEX 0
52 
53 
54 /*
55  * Return fractional part of 'f'.  Used for computing interpolation weights.
56  * Need to be careful with negative values.
57  * Note, if this function isn't perfect you'll sometimes see 1-pixel bands
58  * of improperly weighted linear-filtered textures.
59  * The tests/texwrap.c demo is a good test.
60  */
61 static inline float
frac(float f)62 frac(float f)
63 {
64    return f - floorf(f);
65 }
66 
67 
68 
69 /**
70  * Linear interpolation macro
71  */
72 static inline float
lerp(float a,float v0,float v1)73 lerp(float a, float v0, float v1)
74 {
75    return v0 + a * (v1 - v0);
76 }
77 
78 
79 /**
80  * Do 2D/bilinear interpolation of float values.
81  * v00, v10, v01 and v11 are typically four texture samples in a square/box.
82  * a and b are the horizontal and vertical interpolants.
83  * It's important that this function is inlined when compiled with
84  * optimization!  If we find that's not true on some systems, convert
85  * to a macro.
86  */
87 static inline float
lerp_2d(float a,float b,float v00,float v10,float v01,float v11)88 lerp_2d(float a, float b,
89         float v00, float v10, float v01, float v11)
90 {
91    const float temp0 = lerp(a, v00, v10);
92    const float temp1 = lerp(a, v01, v11);
93    return lerp(b, temp0, temp1);
94 }
95 
96 
97 /**
98  * As above, but 3D interpolation of 8 values.
99  */
100 static inline float
lerp_3d(float a,float b,float c,float v000,float v100,float v010,float v110,float v001,float v101,float v011,float v111)101 lerp_3d(float a, float b, float c,
102         float v000, float v100, float v010, float v110,
103         float v001, float v101, float v011, float v111)
104 {
105    const float temp0 = lerp_2d(a, b, v000, v100, v010, v110);
106    const float temp1 = lerp_2d(a, b, v001, v101, v011, v111);
107    return lerp(c, temp0, temp1);
108 }
109 
110 
111 
112 /**
113  * Compute coord % size for repeat wrap modes.
114  * Note that if coord is negative, coord % size doesn't give the right
115  * value.  To avoid that problem we add a large multiple of the size
116  * (rather than using a conditional).
117  */
118 static inline int
repeat(int coord,unsigned size)119 repeat(int coord, unsigned size)
120 {
121    return (coord + size * 1024) % size;
122 }
123 
124 
125 /**
126  * Apply texture coord wrapping mode and return integer texture indexes
127  * for a vector of four texcoords (S or T or P).
128  * \param wrapMode  PIPE_TEX_WRAP_x
129  * \param s  the incoming texcoords
130  * \param size  the texture image size
131  * \param icoord  returns the integer texcoords
132  */
133 static void
wrap_nearest_repeat(float s,unsigned size,int offset,int * icoord)134 wrap_nearest_repeat(float s, unsigned size, int offset, int *icoord)
135 {
136    /* s limited to [0,1) */
137    /* i limited to [0,size-1] */
138    const int i = util_ifloor(s * size);
139    *icoord = repeat(i + offset, size);
140 }
141 
142 
143 static void
wrap_nearest_clamp(float s,unsigned size,int offset,int * icoord)144 wrap_nearest_clamp(float s, unsigned size, int offset, int *icoord)
145 {
146    /* s limited to [0,1] */
147    /* i limited to [0,size-1] */
148    s *= size;
149    s += offset;
150    if (s <= 0.0F)
151       *icoord = 0;
152    else if (s >= size)
153       *icoord = size - 1;
154    else
155       *icoord = util_ifloor(s);
156 }
157 
158 
159 static void
wrap_nearest_clamp_to_edge(float s,unsigned size,int offset,int * icoord)160 wrap_nearest_clamp_to_edge(float s, unsigned size, int offset, int *icoord)
161 {
162    /* s limited to [min,max] */
163    /* i limited to [0, size-1] */
164    const float min = 0.5F;
165    const float max = (float)size - 0.5F;
166 
167    s *= size;
168    s += offset;
169 
170    if (s < min)
171       *icoord = 0;
172    else if (s > max)
173       *icoord = size - 1;
174    else
175       *icoord = util_ifloor(s);
176 }
177 
178 
179 static void
wrap_nearest_clamp_to_border(float s,unsigned size,int offset,int * icoord)180 wrap_nearest_clamp_to_border(float s, unsigned size, int offset, int *icoord)
181 {
182    /* s limited to [min,max] */
183    /* i limited to [-1, size] */
184    const float min = -0.5F;
185    const float max = size + 0.5F;
186 
187    s *= size;
188    s += offset;
189    if (s <= min)
190       *icoord = -1;
191    else if (s >= max)
192       *icoord = size;
193    else
194       *icoord = util_ifloor(s);
195 }
196 
197 static void
wrap_nearest_mirror_repeat(float s,unsigned size,int offset,int * icoord)198 wrap_nearest_mirror_repeat(float s, unsigned size, int offset, int *icoord)
199 {
200    const float min = 1.0F / (2.0F * size);
201    const float max = 1.0F - min;
202    int flr;
203    float u;
204 
205    s += (float)offset / size;
206    flr = util_ifloor(s);
207    u = frac(s);
208    if (flr & 1)
209       u = 1.0F - u;
210    if (u < min)
211       *icoord = 0;
212    else if (u > max)
213       *icoord = size - 1;
214    else
215       *icoord = util_ifloor(u * size);
216 }
217 
218 
219 static void
wrap_nearest_mirror_clamp(float s,unsigned size,int offset,int * icoord)220 wrap_nearest_mirror_clamp(float s, unsigned size, int offset, int *icoord)
221 {
222    /* s limited to [0,1] */
223    /* i limited to [0,size-1] */
224    const float u = fabsf(s * size + offset);
225    if (u <= 0.0F)
226       *icoord = 0;
227    else if (u >= size)
228       *icoord = size - 1;
229    else
230       *icoord = util_ifloor(u);
231 }
232 
233 
234 static void
wrap_nearest_mirror_clamp_to_edge(float s,unsigned size,int offset,int * icoord)235 wrap_nearest_mirror_clamp_to_edge(float s, unsigned size, int offset, int *icoord)
236 {
237    /* s limited to [min,max] */
238    /* i limited to [0, size-1] */
239    const float min = 0.5F;
240    const float max = (float)size - 0.5F;
241    const float u = fabsf(s * size + offset);
242 
243    if (u < min)
244       *icoord = 0;
245    else if (u > max)
246       *icoord = size - 1;
247    else
248       *icoord = util_ifloor(u);
249 }
250 
251 
252 static void
wrap_nearest_mirror_clamp_to_border(float s,unsigned size,int offset,int * icoord)253 wrap_nearest_mirror_clamp_to_border(float s, unsigned size, int offset, int *icoord)
254 {
255    /* u limited to [-0.5, size-0.5] */
256    const float min = -0.5F;
257    const float max = (float)size + 0.5F;
258    const float u = fabsf(s * size + offset);
259 
260    if (u < min)
261       *icoord = -1;
262    else if (u > max)
263       *icoord = size;
264    else
265       *icoord = util_ifloor(u);
266 }
267 
268 
269 /**
270  * Used to compute texel locations for linear sampling
271  * \param wrapMode  PIPE_TEX_WRAP_x
272  * \param s  the texcoord
273  * \param size  the texture image size
274  * \param icoord0  returns first texture index
275  * \param icoord1  returns second texture index (usually icoord0 + 1)
276  * \param w  returns blend factor/weight between texture indices
277  * \param icoord  returns the computed integer texture coord
278  */
279 static void
wrap_linear_repeat(float s,unsigned size,int offset,int * icoord0,int * icoord1,float * w)280 wrap_linear_repeat(float s, unsigned size, int offset,
281                    int *icoord0, int *icoord1, float *w)
282 {
283    const float u = s * size - 0.5F;
284    *icoord0 = repeat(util_ifloor(u) + offset, size);
285    *icoord1 = repeat(*icoord0 + 1, size);
286    *w = frac(u);
287 }
288 
289 
290 static void
wrap_linear_clamp(float s,unsigned size,int offset,int * icoord0,int * icoord1,float * w)291 wrap_linear_clamp(float s, unsigned size, int offset,
292                   int *icoord0, int *icoord1, float *w)
293 {
294    const float u = CLAMP(s * size + offset, 0.0F, (float)size) - 0.5f;
295 
296    *icoord0 = util_ifloor(u);
297    *icoord1 = *icoord0 + 1;
298    *w = frac(u);
299 }
300 
301 
302 static void
wrap_linear_clamp_to_edge(float s,unsigned size,int offset,int * icoord0,int * icoord1,float * w)303 wrap_linear_clamp_to_edge(float s, unsigned size, int offset,
304                           int *icoord0, int *icoord1, float *w)
305 {
306    const float u = CLAMP(s * size + offset, 0.0F, (float)size) - 0.5f;
307    *icoord0 = util_ifloor(u);
308    *icoord1 = *icoord0 + 1;
309    if (*icoord0 < 0)
310       *icoord0 = 0;
311    if (*icoord1 >= (int) size)
312       *icoord1 = size - 1;
313    *w = frac(u);
314 }
315 
316 
317 static void
wrap_linear_clamp_to_border(float s,unsigned size,int offset,int * icoord0,int * icoord1,float * w)318 wrap_linear_clamp_to_border(float s, unsigned size, int offset,
319                             int *icoord0, int *icoord1, float *w)
320 {
321    const float min = -0.5F;
322    const float max = (float)size + 0.5F;
323    const float u = CLAMP(s * size + offset, min, max) - 0.5f;
324    *icoord0 = util_ifloor(u);
325    *icoord1 = *icoord0 + 1;
326    *w = frac(u);
327 }
328 
329 
330 static void
wrap_linear_mirror_repeat(float s,unsigned size,int offset,int * icoord0,int * icoord1,float * w)331 wrap_linear_mirror_repeat(float s, unsigned size, int offset,
332                           int *icoord0, int *icoord1, float *w)
333 {
334    int flr;
335    float u;
336 
337    s += (float)offset / size;
338    flr = util_ifloor(s);
339    u = frac(s);
340    if (flr & 1)
341       u = 1.0F - u;
342    u = u * size - 0.5F;
343    *icoord0 = util_ifloor(u);
344    *icoord1 = *icoord0 + 1;
345    if (*icoord0 < 0)
346       *icoord0 = 0;
347    if (*icoord1 >= (int) size)
348       *icoord1 = size - 1;
349    *w = frac(u);
350 }
351 
352 
353 static void
wrap_linear_mirror_clamp(float s,unsigned size,int offset,int * icoord0,int * icoord1,float * w)354 wrap_linear_mirror_clamp(float s, unsigned size, int offset,
355                          int *icoord0, int *icoord1, float *w)
356 {
357    float u = fabsf(s * size + offset);
358    if (u >= size)
359       u = (float) size;
360    u -= 0.5F;
361    *icoord0 = util_ifloor(u);
362    *icoord1 = *icoord0 + 1;
363    *w = frac(u);
364 }
365 
366 
367 static void
wrap_linear_mirror_clamp_to_edge(float s,unsigned size,int offset,int * icoord0,int * icoord1,float * w)368 wrap_linear_mirror_clamp_to_edge(float s, unsigned size, int offset,
369                                  int *icoord0, int *icoord1, float *w)
370 {
371    float u = fabsf(s * size + offset);
372    if (u >= size)
373       u = (float) size;
374    u -= 0.5F;
375    *icoord0 = util_ifloor(u);
376    *icoord1 = *icoord0 + 1;
377    if (*icoord0 < 0)
378       *icoord0 = 0;
379    if (*icoord1 >= (int) size)
380       *icoord1 = size - 1;
381    *w = frac(u);
382 }
383 
384 
385 static void
wrap_linear_mirror_clamp_to_border(float s,unsigned size,int offset,int * icoord0,int * icoord1,float * w)386 wrap_linear_mirror_clamp_to_border(float s, unsigned size, int offset,
387                                    int *icoord0, int *icoord1, float *w)
388 {
389    const float min = -0.5F;
390    const float max = size + 0.5F;
391    const float t = fabsf(s * size + offset);
392    const float u = CLAMP(t, min, max) - 0.5F;
393    *icoord0 = util_ifloor(u);
394    *icoord1 = *icoord0 + 1;
395    *w = frac(u);
396 }
397 
398 
399 /**
400  * PIPE_TEX_WRAP_CLAMP for nearest sampling, unnormalized coords.
401  */
402 static void
wrap_nearest_unorm_clamp(float s,unsigned size,int offset,int * icoord)403 wrap_nearest_unorm_clamp(float s, unsigned size, int offset, int *icoord)
404 {
405    const int i = util_ifloor(s);
406    *icoord = CLAMP(i + offset, 0, (int) size-1);
407 }
408 
409 
410 /**
411  * PIPE_TEX_WRAP_CLAMP_TO_BORDER for nearest sampling, unnormalized coords.
412  */
413 static void
wrap_nearest_unorm_clamp_to_border(float s,unsigned size,int offset,int * icoord)414 wrap_nearest_unorm_clamp_to_border(float s, unsigned size, int offset, int *icoord)
415 {
416    *icoord = util_ifloor( CLAMP(s + offset, -0.5F, (float) size + 0.5F) );
417 }
418 
419 
420 /**
421  * PIPE_TEX_WRAP_CLAMP_TO_EDGE for nearest sampling, unnormalized coords.
422  */
423 static void
wrap_nearest_unorm_clamp_to_edge(float s,unsigned size,int offset,int * icoord)424 wrap_nearest_unorm_clamp_to_edge(float s, unsigned size, int offset, int *icoord)
425 {
426    *icoord = util_ifloor( CLAMP(s + offset, 0.5F, (float) size - 0.5F) );
427 }
428 
429 
430 /**
431  * PIPE_TEX_WRAP_CLAMP for linear sampling, unnormalized coords.
432  */
433 static void
wrap_linear_unorm_clamp(float s,unsigned size,int offset,int * icoord0,int * icoord1,float * w)434 wrap_linear_unorm_clamp(float s, unsigned size, int offset,
435                         int *icoord0, int *icoord1, float *w)
436 {
437    /* Not exactly what the spec says, but it matches NVIDIA output */
438    const float u = CLAMP(s + offset - 0.5F, 0.0f, (float) size - 1.0f);
439    *icoord0 = util_ifloor(u);
440    *icoord1 = *icoord0 + 1;
441    *w = frac(u);
442 }
443 
444 
445 /**
446  * PIPE_TEX_WRAP_CLAMP_TO_BORDER for linear sampling, unnormalized coords.
447  */
448 static void
wrap_linear_unorm_clamp_to_border(float s,unsigned size,int offset,int * icoord0,int * icoord1,float * w)449 wrap_linear_unorm_clamp_to_border(float s, unsigned size, int offset,
450                                   int *icoord0, int *icoord1, float *w)
451 {
452    const float u = CLAMP(s + offset, -0.5F, (float) size + 0.5F) - 0.5F;
453    *icoord0 = util_ifloor(u);
454    *icoord1 = *icoord0 + 1;
455    if (*icoord1 > (int) size - 1)
456       *icoord1 = size - 1;
457    *w = frac(u);
458 }
459 
460 
461 /**
462  * PIPE_TEX_WRAP_CLAMP_TO_EDGE for linear sampling, unnormalized coords.
463  */
464 static void
wrap_linear_unorm_clamp_to_edge(float s,unsigned size,int offset,int * icoord0,int * icoord1,float * w)465 wrap_linear_unorm_clamp_to_edge(float s, unsigned size, int offset,
466                                 int *icoord0, int *icoord1, float *w)
467 {
468    const float u = CLAMP(s + offset, +0.5F, (float) size - 0.5F) - 0.5F;
469    *icoord0 = util_ifloor(u);
470    *icoord1 = *icoord0 + 1;
471    if (*icoord1 > (int) size - 1)
472       *icoord1 = size - 1;
473    *w = frac(u);
474 }
475 
476 
477 /**
478  * Do coordinate to array index conversion.  For array textures.
479  */
480 static inline int
coord_to_layer(float coord,unsigned first_layer,unsigned last_layer)481 coord_to_layer(float coord, unsigned first_layer, unsigned last_layer)
482 {
483    const int c = util_ifloor(coord + 0.5F);
484    return CLAMP(c, (int)first_layer, (int)last_layer);
485 }
486 
487 
488 /**
489  * Examine the quad's texture coordinates to compute the partial
490  * derivatives w.r.t X and Y, then compute lambda (level of detail).
491  */
492 static float
compute_lambda_1d(const struct sp_sampler_view * sview,const float s[TGSI_QUAD_SIZE],const float t[TGSI_QUAD_SIZE],const float p[TGSI_QUAD_SIZE])493 compute_lambda_1d(const struct sp_sampler_view *sview,
494                   const float s[TGSI_QUAD_SIZE],
495                   const float t[TGSI_QUAD_SIZE],
496                   const float p[TGSI_QUAD_SIZE])
497 {
498    const struct pipe_resource *texture = sview->base.texture;
499    const float dsdx = fabsf(s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]);
500    const float dsdy = fabsf(s[QUAD_TOP_LEFT]     - s[QUAD_BOTTOM_LEFT]);
501    const float rho = MAX2(dsdx, dsdy) * u_minify(texture->width0, sview->base.u.tex.first_level);
502 
503    return util_fast_log2(rho);
504 }
505 
506 
507 static float
compute_lambda_2d(const struct sp_sampler_view * sview,const float s[TGSI_QUAD_SIZE],const float t[TGSI_QUAD_SIZE],const float p[TGSI_QUAD_SIZE])508 compute_lambda_2d(const struct sp_sampler_view *sview,
509                   const float s[TGSI_QUAD_SIZE],
510                   const float t[TGSI_QUAD_SIZE],
511                   const float p[TGSI_QUAD_SIZE])
512 {
513    const struct pipe_resource *texture = sview->base.texture;
514    const float dsdx = fabsf(s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]);
515    const float dsdy = fabsf(s[QUAD_TOP_LEFT]     - s[QUAD_BOTTOM_LEFT]);
516    const float dtdx = fabsf(t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT]);
517    const float dtdy = fabsf(t[QUAD_TOP_LEFT]     - t[QUAD_BOTTOM_LEFT]);
518    const float maxx = MAX2(dsdx, dsdy) * u_minify(texture->width0, sview->base.u.tex.first_level);
519    const float maxy = MAX2(dtdx, dtdy) * u_minify(texture->height0, sview->base.u.tex.first_level);
520    const float rho  = MAX2(maxx, maxy);
521 
522    return util_fast_log2(rho);
523 }
524 
525 
526 static float
compute_lambda_3d(const struct sp_sampler_view * sview,const float s[TGSI_QUAD_SIZE],const float t[TGSI_QUAD_SIZE],const float p[TGSI_QUAD_SIZE])527 compute_lambda_3d(const struct sp_sampler_view *sview,
528                   const float s[TGSI_QUAD_SIZE],
529                   const float t[TGSI_QUAD_SIZE],
530                   const float p[TGSI_QUAD_SIZE])
531 {
532    const struct pipe_resource *texture = sview->base.texture;
533    const float dsdx = fabsf(s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]);
534    const float dsdy = fabsf(s[QUAD_TOP_LEFT]     - s[QUAD_BOTTOM_LEFT]);
535    const float dtdx = fabsf(t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT]);
536    const float dtdy = fabsf(t[QUAD_TOP_LEFT]     - t[QUAD_BOTTOM_LEFT]);
537    const float dpdx = fabsf(p[QUAD_BOTTOM_RIGHT] - p[QUAD_BOTTOM_LEFT]);
538    const float dpdy = fabsf(p[QUAD_TOP_LEFT]     - p[QUAD_BOTTOM_LEFT]);
539    const float maxx = MAX2(dsdx, dsdy) * u_minify(texture->width0, sview->base.u.tex.first_level);
540    const float maxy = MAX2(dtdx, dtdy) * u_minify(texture->height0, sview->base.u.tex.first_level);
541    const float maxz = MAX2(dpdx, dpdy) * u_minify(texture->depth0, sview->base.u.tex.first_level);
542    const float rho = MAX3(maxx, maxy, maxz);
543 
544    return util_fast_log2(rho);
545 }
546 
547 
548 /**
549  * Compute lambda for a vertex texture sampler.
550  * Since there aren't derivatives to use, just return 0.
551  */
552 static float
compute_lambda_vert(const struct sp_sampler_view * sview,const float s[TGSI_QUAD_SIZE],const float t[TGSI_QUAD_SIZE],const float p[TGSI_QUAD_SIZE])553 compute_lambda_vert(const struct sp_sampler_view *sview,
554                     const float s[TGSI_QUAD_SIZE],
555                     const float t[TGSI_QUAD_SIZE],
556                     const float p[TGSI_QUAD_SIZE])
557 {
558    return 0.0f;
559 }
560 
561 
562 
563 /**
564  * Get a texel from a texture, using the texture tile cache.
565  *
566  * \param addr  the template tex address containing cube, z, face info.
567  * \param x  the x coord of texel within 2D image
568  * \param y  the y coord of texel within 2D image
569  * \param rgba  the quad to put the texel/color into
570  *
571  * XXX maybe move this into sp_tex_tile_cache.c and merge with the
572  * sp_get_cached_tile_tex() function.
573  */
574 
575 
576 
577 
578 static inline const float *
get_texel_2d_no_border(const struct sp_sampler_view * sp_sview,union tex_tile_address addr,int x,int y)579 get_texel_2d_no_border(const struct sp_sampler_view *sp_sview,
580                        union tex_tile_address addr, int x, int y)
581 {
582    const struct softpipe_tex_cached_tile *tile;
583    addr.bits.x = x / TEX_TILE_SIZE;
584    addr.bits.y = y / TEX_TILE_SIZE;
585    y %= TEX_TILE_SIZE;
586    x %= TEX_TILE_SIZE;
587 
588    tile = sp_get_cached_tile_tex(sp_sview->cache, addr);
589 
590    return &tile->data.color[y][x][0];
591 }
592 
593 
594 static inline const float *
get_texel_2d(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,union tex_tile_address addr,int x,int y)595 get_texel_2d(const struct sp_sampler_view *sp_sview,
596              const struct sp_sampler *sp_samp,
597              union tex_tile_address addr, int x, int y)
598 {
599    const struct pipe_resource *texture = sp_sview->base.texture;
600    const unsigned level = addr.bits.level;
601 
602    if (x < 0 || x >= (int) u_minify(texture->width0, level) ||
603        y < 0 || y >= (int) u_minify(texture->height0, level)) {
604       return sp_samp->base.border_color.f;
605    }
606    else {
607       return get_texel_2d_no_border( sp_sview, addr, x, y );
608    }
609 }
610 
611 
612 /*
613  * Here's the complete logic (HOLY CRAP) for finding next face and doing the
614  * corresponding coord wrapping, implemented by get_next_face,
615  * get_next_xcoord, get_next_ycoord.
616  * Read like that (first line):
617  * If face is +x and s coord is below zero, then
618  * new face is +z, new s is max , new t is old t
619  * (max is always cube size - 1).
620  *
621  * +x s- -> +z: s = max,   t = t
622  * +x s+ -> -z: s = 0,     t = t
623  * +x t- -> +y: s = max,   t = max-s
624  * +x t+ -> -y: s = max,   t = s
625  *
626  * -x s- -> -z: s = max,   t = t
627  * -x s+ -> +z: s = 0,     t = t
628  * -x t- -> +y: s = 0,     t = s
629  * -x t+ -> -y: s = 0,     t = max-s
630  *
631  * +y s- -> -x: s = t,     t = 0
632  * +y s+ -> +x: s = max-t, t = 0
633  * +y t- -> -z: s = max-s, t = 0
634  * +y t+ -> +z: s = s,     t = 0
635  *
636  * -y s- -> -x: s = max-t, t = max
637  * -y s+ -> +x: s = t,     t = max
638  * -y t- -> +z: s = s,     t = max
639  * -y t+ -> -z: s = max-s, t = max
640 
641  * +z s- -> -x: s = max,   t = t
642  * +z s+ -> +x: s = 0,     t = t
643  * +z t- -> +y: s = s,     t = max
644  * +z t+ -> -y: s = s,     t = 0
645 
646  * -z s- -> +x: s = max,   t = t
647  * -z s+ -> -x: s = 0,     t = t
648  * -z t- -> +y: s = max-s, t = 0
649  * -z t+ -> -y: s = max-s, t = max
650  */
651 
652 
653 /*
654  * seamless cubemap neighbour array.
655  * this array is used to find the adjacent face in each of 4 directions,
656  * left, right, up, down. (or -x, +x, -y, +y).
657  */
658 static const unsigned face_array[PIPE_TEX_FACE_MAX][4] = {
659    /* pos X first then neg X is Z different, Y the same */
660    /* PIPE_TEX_FACE_POS_X,*/
661    { PIPE_TEX_FACE_POS_Z, PIPE_TEX_FACE_NEG_Z,
662      PIPE_TEX_FACE_POS_Y, PIPE_TEX_FACE_NEG_Y },
663    /* PIPE_TEX_FACE_NEG_X */
664    { PIPE_TEX_FACE_NEG_Z, PIPE_TEX_FACE_POS_Z,
665      PIPE_TEX_FACE_POS_Y, PIPE_TEX_FACE_NEG_Y },
666 
667    /* pos Y first then neg Y is X different, X the same */
668    /* PIPE_TEX_FACE_POS_Y */
669    { PIPE_TEX_FACE_NEG_X, PIPE_TEX_FACE_POS_X,
670      PIPE_TEX_FACE_NEG_Z, PIPE_TEX_FACE_POS_Z },
671 
672    /* PIPE_TEX_FACE_NEG_Y */
673    { PIPE_TEX_FACE_NEG_X, PIPE_TEX_FACE_POS_X,
674      PIPE_TEX_FACE_POS_Z, PIPE_TEX_FACE_NEG_Z },
675 
676    /* pos Z first then neg Y is X different, X the same */
677    /* PIPE_TEX_FACE_POS_Z */
678    { PIPE_TEX_FACE_NEG_X, PIPE_TEX_FACE_POS_X,
679      PIPE_TEX_FACE_POS_Y, PIPE_TEX_FACE_NEG_Y },
680 
681    /* PIPE_TEX_FACE_NEG_Z */
682    { PIPE_TEX_FACE_POS_X, PIPE_TEX_FACE_NEG_X,
683      PIPE_TEX_FACE_POS_Y, PIPE_TEX_FACE_NEG_Y }
684 };
685 
686 static inline unsigned
get_next_face(unsigned face,int idx)687 get_next_face(unsigned face, int idx)
688 {
689    return face_array[face][idx];
690 }
691 
692 /*
693  * return a new xcoord based on old face, old coords, cube size
694  * and fall_off_index (0 for x-, 1 for x+, 2 for y-, 3 for y+)
695  */
696 static inline int
get_next_xcoord(unsigned face,unsigned fall_off_index,int max,int xc,int yc)697 get_next_xcoord(unsigned face, unsigned fall_off_index, int max, int xc, int yc)
698 {
699    if ((face == 0 && fall_off_index != 1) ||
700        (face == 1 && fall_off_index == 0) ||
701        (face == 4 && fall_off_index == 0) ||
702        (face == 5 && fall_off_index == 0)) {
703       return max;
704    }
705    if ((face == 1 && fall_off_index != 0) ||
706        (face == 0 && fall_off_index == 1) ||
707        (face == 4 && fall_off_index == 1) ||
708        (face == 5 && fall_off_index == 1)) {
709       return 0;
710    }
711    if ((face == 4 && fall_off_index >= 2) ||
712        (face == 2 && fall_off_index == 3) ||
713        (face == 3 && fall_off_index == 2)) {
714       return xc;
715    }
716    if ((face == 5 && fall_off_index >= 2) ||
717        (face == 2 && fall_off_index == 2) ||
718        (face == 3 && fall_off_index == 3)) {
719       return max - xc;
720    }
721    if ((face == 2 && fall_off_index == 0) ||
722        (face == 3 && fall_off_index == 1)) {
723       return yc;
724    }
725    /* (face == 2 && fall_off_index == 1) ||
726       (face == 3 && fall_off_index == 0)) */
727    return max - yc;
728 }
729 
730 /*
731  * return a new ycoord based on old face, old coords, cube size
732  * and fall_off_index (0 for x-, 1 for x+, 2 for y-, 3 for y+)
733  */
734 static inline int
get_next_ycoord(unsigned face,unsigned fall_off_index,int max,int xc,int yc)735 get_next_ycoord(unsigned face, unsigned fall_off_index, int max, int xc, int yc)
736 {
737    if ((fall_off_index <= 1) && (face <= 1 || face >= 4)) {
738       return yc;
739    }
740    if (face == 2 ||
741        (face == 4 && fall_off_index == 3) ||
742        (face == 5 && fall_off_index == 2)) {
743       return 0;
744    }
745    if (face == 3 ||
746        (face == 4 && fall_off_index == 2) ||
747        (face == 5 && fall_off_index == 3)) {
748       return max;
749    }
750    if ((face == 0 && fall_off_index == 3) ||
751        (face == 1 && fall_off_index == 2)) {
752       return xc;
753    }
754    /* (face == 0 && fall_off_index == 2) ||
755       (face == 1 && fall_off_index == 3) */
756    return max - xc;
757 }
758 
759 
760 /* Gather a quad of adjacent texels within a tile:
761  */
762 static inline void
get_texel_quad_2d_no_border_single_tile(const struct sp_sampler_view * sp_sview,union tex_tile_address addr,unsigned x,unsigned y,const float * out[4])763 get_texel_quad_2d_no_border_single_tile(const struct sp_sampler_view *sp_sview,
764                                         union tex_tile_address addr,
765                                         unsigned x, unsigned y,
766                                         const float *out[4])
767 {
768     const struct softpipe_tex_cached_tile *tile;
769 
770    addr.bits.x = x / TEX_TILE_SIZE;
771    addr.bits.y = y / TEX_TILE_SIZE;
772    y %= TEX_TILE_SIZE;
773    x %= TEX_TILE_SIZE;
774 
775    tile = sp_get_cached_tile_tex(sp_sview->cache, addr);
776 
777    out[0] = &tile->data.color[y  ][x  ][0];
778    out[1] = &tile->data.color[y  ][x+1][0];
779    out[2] = &tile->data.color[y+1][x  ][0];
780    out[3] = &tile->data.color[y+1][x+1][0];
781 }
782 
783 
784 /* Gather a quad of potentially non-adjacent texels:
785  */
786 static inline void
get_texel_quad_2d_no_border(const struct sp_sampler_view * sp_sview,union tex_tile_address addr,int x0,int y0,int x1,int y1,const float * out[4])787 get_texel_quad_2d_no_border(const struct sp_sampler_view *sp_sview,
788                             union tex_tile_address addr,
789                             int x0, int y0,
790                             int x1, int y1,
791                             const float *out[4])
792 {
793    out[0] = get_texel_2d_no_border( sp_sview, addr, x0, y0 );
794    out[1] = get_texel_2d_no_border( sp_sview, addr, x1, y0 );
795    out[2] = get_texel_2d_no_border( sp_sview, addr, x0, y1 );
796    out[3] = get_texel_2d_no_border( sp_sview, addr, x1, y1 );
797 }
798 
799 /* Can involve a lot of unnecessary checks for border color:
800  */
801 static inline void
get_texel_quad_2d(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,union tex_tile_address addr,int x0,int y0,int x1,int y1,const float * out[4])802 get_texel_quad_2d(const struct sp_sampler_view *sp_sview,
803                   const struct sp_sampler *sp_samp,
804                   union tex_tile_address addr,
805                   int x0, int y0,
806                   int x1, int y1,
807                   const float *out[4])
808 {
809    out[0] = get_texel_2d( sp_sview, sp_samp, addr, x0, y0 );
810    out[1] = get_texel_2d( sp_sview, sp_samp, addr, x1, y0 );
811    out[3] = get_texel_2d( sp_sview, sp_samp, addr, x1, y1 );
812    out[2] = get_texel_2d( sp_sview, sp_samp, addr, x0, y1 );
813 }
814 
815 
816 
817 /* 3d variants:
818  */
819 static inline const float *
get_texel_3d_no_border(const struct sp_sampler_view * sp_sview,union tex_tile_address addr,int x,int y,int z)820 get_texel_3d_no_border(const struct sp_sampler_view *sp_sview,
821                        union tex_tile_address addr, int x, int y, int z)
822 {
823    const struct softpipe_tex_cached_tile *tile;
824 
825    addr.bits.x = x / TEX_TILE_SIZE;
826    addr.bits.y = y / TEX_TILE_SIZE;
827    addr.bits.z = z;
828    y %= TEX_TILE_SIZE;
829    x %= TEX_TILE_SIZE;
830 
831    tile = sp_get_cached_tile_tex(sp_sview->cache, addr);
832 
833    return &tile->data.color[y][x][0];
834 }
835 
836 
837 static inline const float *
get_texel_3d(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,union tex_tile_address addr,int x,int y,int z)838 get_texel_3d(const struct sp_sampler_view *sp_sview,
839              const struct sp_sampler *sp_samp,
840              union tex_tile_address addr, int x, int y, int z)
841 {
842    const struct pipe_resource *texture = sp_sview->base.texture;
843    const unsigned level = addr.bits.level;
844 
845    if (x < 0 || x >= (int) u_minify(texture->width0, level) ||
846        y < 0 || y >= (int) u_minify(texture->height0, level) ||
847        z < 0 || z >= (int) u_minify(texture->depth0, level)) {
848       return sp_samp->base.border_color.f;
849    }
850    else {
851       return get_texel_3d_no_border( sp_sview, addr, x, y, z );
852    }
853 }
854 
855 
856 /* Get texel pointer for 1D array texture */
857 static inline const float *
get_texel_1d_array(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,union tex_tile_address addr,int x,int y)858 get_texel_1d_array(const struct sp_sampler_view *sp_sview,
859                    const struct sp_sampler *sp_samp,
860                    union tex_tile_address addr, int x, int y)
861 {
862    const struct pipe_resource *texture = sp_sview->base.texture;
863    const unsigned level = addr.bits.level;
864 
865    if (x < 0 || x >= (int) u_minify(texture->width0, level)) {
866       return sp_samp->base.border_color.f;
867    }
868    else {
869       return get_texel_2d_no_border(sp_sview, addr, x, y);
870    }
871 }
872 
873 
874 /* Get texel pointer for 2D array texture */
875 static inline const float *
get_texel_2d_array(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,union tex_tile_address addr,int x,int y,int layer)876 get_texel_2d_array(const struct sp_sampler_view *sp_sview,
877                    const struct sp_sampler *sp_samp,
878                    union tex_tile_address addr, int x, int y, int layer)
879 {
880    const struct pipe_resource *texture = sp_sview->base.texture;
881    const unsigned level = addr.bits.level;
882 
883    assert(layer < (int) texture->array_size);
884    assert(layer >= 0);
885 
886    if (x < 0 || x >= (int) u_minify(texture->width0, level) ||
887        y < 0 || y >= (int) u_minify(texture->height0, level)) {
888       return sp_samp->base.border_color.f;
889    }
890    else {
891       return get_texel_3d_no_border(sp_sview, addr, x, y, layer);
892    }
893 }
894 
895 
896 static inline const float *
get_texel_cube_seamless(const struct sp_sampler_view * sp_sview,union tex_tile_address addr,int x,int y,float * corner,int layer,unsigned face)897 get_texel_cube_seamless(const struct sp_sampler_view *sp_sview,
898                         union tex_tile_address addr, int x, int y,
899                         float *corner, int layer, unsigned face)
900 {
901    const struct pipe_resource *texture = sp_sview->base.texture;
902    const unsigned level = addr.bits.level;
903    int new_x, new_y, max_x;
904 
905    max_x = (int) u_minify(texture->width0, level);
906 
907    assert(texture->width0 == texture->height0);
908    new_x = x;
909    new_y = y;
910 
911    /* change the face */
912    if (x < 0) {
913       /*
914        * Cheat with corners. They are difficult and I believe because we don't get
915        * per-pixel faces we can actually have multiple corner texels per pixel,
916        * which screws things up majorly in any case (as the per spec behavior is
917        * to average the 3 remaining texels, which we might not have).
918        * Hence just make sure that the 2nd coord is clamped, will simply pick the
919        * sample which would have fallen off the x coord, but not y coord.
920        * So the filter weight of the samples will be wrong, but at least this
921        * ensures that only valid texels near the corner are used.
922        */
923       if (y < 0 || y >= max_x) {
924          y = CLAMP(y, 0, max_x - 1);
925       }
926       new_x = get_next_xcoord(face, 0, max_x -1, x, y);
927       new_y = get_next_ycoord(face, 0, max_x -1, x, y);
928       face = get_next_face(face, 0);
929    } else if (x >= max_x) {
930       if (y < 0 || y >= max_x) {
931          y = CLAMP(y, 0, max_x - 1);
932       }
933       new_x = get_next_xcoord(face, 1, max_x -1, x, y);
934       new_y = get_next_ycoord(face, 1, max_x -1, x, y);
935       face = get_next_face(face, 1);
936    } else if (y < 0) {
937       new_x = get_next_xcoord(face, 2, max_x -1, x, y);
938       new_y = get_next_ycoord(face, 2, max_x -1, x, y);
939       face = get_next_face(face, 2);
940    } else if (y >= max_x) {
941       new_x = get_next_xcoord(face, 3, max_x -1, x, y);
942       new_y = get_next_ycoord(face, 3, max_x -1, x, y);
943       face = get_next_face(face, 3);
944    }
945 
946    return get_texel_3d_no_border(sp_sview, addr, new_x, new_y, layer + face);
947 }
948 
949 
950 /* Get texel pointer for cube array texture */
951 static inline const float *
get_texel_cube_array(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,union tex_tile_address addr,int x,int y,int layer)952 get_texel_cube_array(const struct sp_sampler_view *sp_sview,
953                      const struct sp_sampler *sp_samp,
954                      union tex_tile_address addr, int x, int y, int layer)
955 {
956    const struct pipe_resource *texture = sp_sview->base.texture;
957    const unsigned level = addr.bits.level;
958 
959    assert(layer < (int) texture->array_size);
960    assert(layer >= 0);
961 
962    if (x < 0 || x >= (int) u_minify(texture->width0, level) ||
963        y < 0 || y >= (int) u_minify(texture->height0, level)) {
964       return sp_samp->base.border_color.f;
965    }
966    else {
967       return get_texel_3d_no_border(sp_sview, addr, x, y, layer);
968    }
969 }
970 /**
971  * Given the logbase2 of a mipmap's base level size and a mipmap level,
972  * return the size (in texels) of that mipmap level.
973  * For example, if level[0].width = 256 then base_pot will be 8.
974  * If level = 2, then we'll return 64 (the width at level=2).
975  * Return 1 if level > base_pot.
976  */
977 static inline unsigned
pot_level_size(unsigned base_pot,unsigned level)978 pot_level_size(unsigned base_pot, unsigned level)
979 {
980    return (base_pot >= level) ? (1 << (base_pot - level)) : 1;
981 }
982 
983 
984 static void
print_sample(const char * function,const float * rgba)985 print_sample(const char *function, const float *rgba)
986 {
987    debug_printf("%s %g %g %g %g\n",
988                 function,
989                 rgba[0], rgba[TGSI_NUM_CHANNELS], rgba[2*TGSI_NUM_CHANNELS], rgba[3*TGSI_NUM_CHANNELS]);
990 }
991 
992 
993 static void
print_sample_4(const char * function,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])994 print_sample_4(const char *function, float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
995 {
996    debug_printf("%s %g %g %g %g, %g %g %g %g, %g %g %g %g, %g %g %g %g\n",
997                 function,
998                 rgba[0][0], rgba[1][0], rgba[2][0], rgba[3][0],
999                 rgba[0][1], rgba[1][1], rgba[2][1], rgba[3][1],
1000                 rgba[0][2], rgba[1][2], rgba[2][2], rgba[3][2],
1001                 rgba[0][3], rgba[1][3], rgba[2][3], rgba[3][3]);
1002 }
1003 
1004 
1005 /* Some image-filter fastpaths:
1006  */
1007 static inline void
img_filter_2d_linear_repeat_POT(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const struct img_filter_args * args,float * rgba)1008 img_filter_2d_linear_repeat_POT(const struct sp_sampler_view *sp_sview,
1009                                 const struct sp_sampler *sp_samp,
1010                                 const struct img_filter_args *args,
1011                                 float *rgba)
1012 {
1013    const unsigned xpot = pot_level_size(sp_sview->xpot, args->level);
1014    const unsigned ypot = pot_level_size(sp_sview->ypot, args->level);
1015    const int xmax = (xpot - 1) & (TEX_TILE_SIZE - 1); /* MIN2(TEX_TILE_SIZE, xpot) - 1; */
1016    const int ymax = (ypot - 1) & (TEX_TILE_SIZE - 1); /* MIN2(TEX_TILE_SIZE, ypot) - 1; */
1017    union tex_tile_address addr;
1018    int c;
1019 
1020    const float u = (args->s * xpot - 0.5F) + args->offset[0];
1021    const float v = (args->t * ypot - 0.5F) + args->offset[1];
1022 
1023    const int uflr = util_ifloor(u);
1024    const int vflr = util_ifloor(v);
1025 
1026    const float xw = u - (float)uflr;
1027    const float yw = v - (float)vflr;
1028 
1029    const int x0 = uflr & (xpot - 1);
1030    const int y0 = vflr & (ypot - 1);
1031 
1032    const float *tx[4];
1033 
1034    addr.value = 0;
1035    addr.bits.level = args->level;
1036    addr.bits.z = sp_sview->base.u.tex.first_layer;
1037 
1038    /* Can we fetch all four at once:
1039     */
1040    if (x0 < xmax && y0 < ymax) {
1041       get_texel_quad_2d_no_border_single_tile(sp_sview, addr, x0, y0, tx);
1042    }
1043    else {
1044       const unsigned x1 = (x0 + 1) & (xpot - 1);
1045       const unsigned y1 = (y0 + 1) & (ypot - 1);
1046       get_texel_quad_2d_no_border(sp_sview, addr, x0, y0, x1, y1, tx);
1047    }
1048 
1049    /* interpolate R, G, B, A */
1050    for (c = 0; c < TGSI_NUM_CHANNELS; c++) {
1051       rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw,
1052                                        tx[0][c], tx[1][c],
1053                                        tx[2][c], tx[3][c]);
1054    }
1055 
1056    if (DEBUG_TEX) {
1057       print_sample(__FUNCTION__, rgba);
1058    }
1059 }
1060 
1061 
1062 static inline void
img_filter_2d_nearest_repeat_POT(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const struct img_filter_args * args,float * rgba)1063 img_filter_2d_nearest_repeat_POT(const struct sp_sampler_view *sp_sview,
1064                                  const struct sp_sampler *sp_samp,
1065                                  const struct img_filter_args *args,
1066                                  float *rgba)
1067 {
1068    const unsigned xpot = pot_level_size(sp_sview->xpot, args->level);
1069    const unsigned ypot = pot_level_size(sp_sview->ypot, args->level);
1070    const float *out;
1071    union tex_tile_address addr;
1072    int c;
1073 
1074    const float u = args->s * xpot + args->offset[0];
1075    const float v = args->t * ypot + args->offset[1];
1076 
1077    const int uflr = util_ifloor(u);
1078    const int vflr = util_ifloor(v);
1079 
1080    const int x0 = uflr & (xpot - 1);
1081    const int y0 = vflr & (ypot - 1);
1082 
1083    addr.value = 0;
1084    addr.bits.level = args->level;
1085    addr.bits.z = sp_sview->base.u.tex.first_layer;
1086 
1087    out = get_texel_2d_no_border(sp_sview, addr, x0, y0);
1088    for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1089       rgba[TGSI_NUM_CHANNELS*c] = out[c];
1090 
1091    if (DEBUG_TEX) {
1092       print_sample(__FUNCTION__, rgba);
1093    }
1094 }
1095 
1096 
1097 static inline void
img_filter_2d_nearest_clamp_POT(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const struct img_filter_args * args,float * rgba)1098 img_filter_2d_nearest_clamp_POT(const struct sp_sampler_view *sp_sview,
1099                                 const struct sp_sampler *sp_samp,
1100                                 const struct img_filter_args *args,
1101                                 float *rgba)
1102 {
1103    const unsigned xpot = pot_level_size(sp_sview->xpot, args->level);
1104    const unsigned ypot = pot_level_size(sp_sview->ypot, args->level);
1105    union tex_tile_address addr;
1106    int c;
1107 
1108    const float u = args->s * xpot + args->offset[0];
1109    const float v = args->t * ypot + args->offset[1];
1110 
1111    int x0, y0;
1112    const float *out;
1113 
1114    addr.value = 0;
1115    addr.bits.level = args->level;
1116    addr.bits.z = sp_sview->base.u.tex.first_layer;
1117 
1118    x0 = util_ifloor(u);
1119    if (x0 < 0)
1120       x0 = 0;
1121    else if (x0 > (int) xpot - 1)
1122       x0 = xpot - 1;
1123 
1124    y0 = util_ifloor(v);
1125    if (y0 < 0)
1126       y0 = 0;
1127    else if (y0 > (int) ypot - 1)
1128       y0 = ypot - 1;
1129 
1130    out = get_texel_2d_no_border(sp_sview, addr, x0, y0);
1131    for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1132       rgba[TGSI_NUM_CHANNELS*c] = out[c];
1133 
1134    if (DEBUG_TEX) {
1135       print_sample(__FUNCTION__, rgba);
1136    }
1137 }
1138 
1139 
1140 static void
img_filter_1d_nearest(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const struct img_filter_args * args,float * rgba)1141 img_filter_1d_nearest(const struct sp_sampler_view *sp_sview,
1142                       const struct sp_sampler *sp_samp,
1143                       const struct img_filter_args *args,
1144                       float *rgba)
1145 {
1146    const struct pipe_resource *texture = sp_sview->base.texture;
1147    const int width = u_minify(texture->width0, args->level);
1148    int x;
1149    union tex_tile_address addr;
1150    const float *out;
1151    int c;
1152 
1153    assert(width > 0);
1154 
1155    addr.value = 0;
1156    addr.bits.level = args->level;
1157 
1158    sp_samp->nearest_texcoord_s(args->s, width, args->offset[0], &x);
1159 
1160    out = get_texel_1d_array(sp_sview, sp_samp, addr, x,
1161                             sp_sview->base.u.tex.first_layer);
1162    for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1163       rgba[TGSI_NUM_CHANNELS*c] = out[c];
1164 
1165    if (DEBUG_TEX) {
1166       print_sample(__FUNCTION__, rgba);
1167    }
1168 }
1169 
1170 
1171 static void
img_filter_1d_array_nearest(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const struct img_filter_args * args,float * rgba)1172 img_filter_1d_array_nearest(const struct sp_sampler_view *sp_sview,
1173                             const struct sp_sampler *sp_samp,
1174                             const struct img_filter_args *args,
1175                             float *rgba)
1176 {
1177    const struct pipe_resource *texture = sp_sview->base.texture;
1178    const int width = u_minify(texture->width0, args->level);
1179    const int layer = coord_to_layer(args->t, sp_sview->base.u.tex.first_layer,
1180                                     sp_sview->base.u.tex.last_layer);
1181    int x;
1182    union tex_tile_address addr;
1183    const float *out;
1184    int c;
1185 
1186    assert(width > 0);
1187 
1188    addr.value = 0;
1189    addr.bits.level = args->level;
1190 
1191    sp_samp->nearest_texcoord_s(args->s, width, args->offset[0], &x);
1192 
1193    out = get_texel_1d_array(sp_sview, sp_samp, addr, x, layer);
1194    for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1195       rgba[TGSI_NUM_CHANNELS*c] = out[c];
1196 
1197    if (DEBUG_TEX) {
1198       print_sample(__FUNCTION__, rgba);
1199    }
1200 }
1201 
1202 
1203 static void
img_filter_2d_nearest(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const struct img_filter_args * args,float * rgba)1204 img_filter_2d_nearest(const struct sp_sampler_view *sp_sview,
1205                       const struct sp_sampler *sp_samp,
1206                       const struct img_filter_args *args,
1207                       float *rgba)
1208 {
1209    const struct pipe_resource *texture = sp_sview->base.texture;
1210    const int width = u_minify(texture->width0, args->level);
1211    const int height = u_minify(texture->height0, args->level);
1212    int x, y;
1213    union tex_tile_address addr;
1214    const float *out;
1215    int c;
1216 
1217    assert(width > 0);
1218    assert(height > 0);
1219 
1220    addr.value = 0;
1221    addr.bits.level = args->level;
1222    addr.bits.z = sp_sview->base.u.tex.first_layer;
1223 
1224    sp_samp->nearest_texcoord_s(args->s, width, args->offset[0], &x);
1225    sp_samp->nearest_texcoord_t(args->t, height, args->offset[1], &y);
1226 
1227    out = get_texel_2d(sp_sview, sp_samp, addr, x, y);
1228    for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1229       rgba[TGSI_NUM_CHANNELS*c] = out[c];
1230 
1231    if (DEBUG_TEX) {
1232       print_sample(__FUNCTION__, rgba);
1233    }
1234 }
1235 
1236 
1237 static void
img_filter_2d_array_nearest(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const struct img_filter_args * args,float * rgba)1238 img_filter_2d_array_nearest(const struct sp_sampler_view *sp_sview,
1239                             const struct sp_sampler *sp_samp,
1240                             const struct img_filter_args *args,
1241                             float *rgba)
1242 {
1243    const struct pipe_resource *texture = sp_sview->base.texture;
1244    const int width = u_minify(texture->width0, args->level);
1245    const int height = u_minify(texture->height0, args->level);
1246    const int layer = coord_to_layer(args->p, sp_sview->base.u.tex.first_layer,
1247                                     sp_sview->base.u.tex.last_layer);
1248    int x, y;
1249    union tex_tile_address addr;
1250    const float *out;
1251    int c;
1252 
1253    assert(width > 0);
1254    assert(height > 0);
1255 
1256    addr.value = 0;
1257    addr.bits.level = args->level;
1258 
1259    sp_samp->nearest_texcoord_s(args->s, width, args->offset[0], &x);
1260    sp_samp->nearest_texcoord_t(args->t, height, args->offset[1], &y);
1261 
1262    out = get_texel_2d_array(sp_sview, sp_samp, addr, x, y, layer);
1263    for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1264       rgba[TGSI_NUM_CHANNELS*c] = out[c];
1265 
1266    if (DEBUG_TEX) {
1267       print_sample(__FUNCTION__, rgba);
1268    }
1269 }
1270 
1271 
1272 static void
img_filter_cube_nearest(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const struct img_filter_args * args,float * rgba)1273 img_filter_cube_nearest(const struct sp_sampler_view *sp_sview,
1274                         const struct sp_sampler *sp_samp,
1275                         const struct img_filter_args *args,
1276                         float *rgba)
1277 {
1278    const struct pipe_resource *texture = sp_sview->base.texture;
1279    const int width = u_minify(texture->width0, args->level);
1280    const int height = u_minify(texture->height0, args->level);
1281    const int layerface = args->face_id + sp_sview->base.u.tex.first_layer;
1282    int x, y;
1283    union tex_tile_address addr;
1284    const float *out;
1285    int c;
1286 
1287    assert(width > 0);
1288    assert(height > 0);
1289 
1290    addr.value = 0;
1291    addr.bits.level = args->level;
1292 
1293    /*
1294     * If NEAREST filtering is done within a miplevel, always apply wrap
1295     * mode CLAMP_TO_EDGE.
1296     */
1297    if (sp_samp->base.seamless_cube_map) {
1298       wrap_nearest_clamp_to_edge(args->s, width, args->offset[0], &x);
1299       wrap_nearest_clamp_to_edge(args->t, height, args->offset[1], &y);
1300    } else {
1301       /* Would probably make sense to ignore mode and just do edge clamp */
1302       sp_samp->nearest_texcoord_s(args->s, width, args->offset[0], &x);
1303       sp_samp->nearest_texcoord_t(args->t, height, args->offset[1], &y);
1304    }
1305 
1306    out = get_texel_cube_array(sp_sview, sp_samp, addr, x, y, layerface);
1307    for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1308       rgba[TGSI_NUM_CHANNELS*c] = out[c];
1309 
1310    if (DEBUG_TEX) {
1311       print_sample(__FUNCTION__, rgba);
1312    }
1313 }
1314 
1315 static void
img_filter_cube_array_nearest(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const struct img_filter_args * args,float * rgba)1316 img_filter_cube_array_nearest(const struct sp_sampler_view *sp_sview,
1317                               const struct sp_sampler *sp_samp,
1318                               const struct img_filter_args *args,
1319                               float *rgba)
1320 {
1321    const struct pipe_resource *texture = sp_sview->base.texture;
1322    const int width = u_minify(texture->width0, args->level);
1323    const int height = u_minify(texture->height0, args->level);
1324    const int layerface =
1325       coord_to_layer(6 * args->p + sp_sview->base.u.tex.first_layer,
1326                      sp_sview->base.u.tex.first_layer,
1327                      sp_sview->base.u.tex.last_layer - 5) + args->face_id;
1328    int x, y;
1329    union tex_tile_address addr;
1330    const float *out;
1331    int c;
1332 
1333    assert(width > 0);
1334    assert(height > 0);
1335 
1336    addr.value = 0;
1337    addr.bits.level = args->level;
1338 
1339    sp_samp->nearest_texcoord_s(args->s, width, args->offset[0], &x);
1340    sp_samp->nearest_texcoord_t(args->t, height, args->offset[1], &y);
1341 
1342    out = get_texel_cube_array(sp_sview, sp_samp, addr, x, y, layerface);
1343    for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1344       rgba[TGSI_NUM_CHANNELS*c] = out[c];
1345 
1346    if (DEBUG_TEX) {
1347       print_sample(__FUNCTION__, rgba);
1348    }
1349 }
1350 
1351 static void
img_filter_3d_nearest(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const struct img_filter_args * args,float * rgba)1352 img_filter_3d_nearest(const struct sp_sampler_view *sp_sview,
1353                       const struct sp_sampler *sp_samp,
1354                       const struct img_filter_args *args,
1355                       float *rgba)
1356 {
1357    const struct pipe_resource *texture = sp_sview->base.texture;
1358    const int width = u_minify(texture->width0, args->level);
1359    const int height = u_minify(texture->height0, args->level);
1360    const int depth = u_minify(texture->depth0, args->level);
1361    int x, y, z;
1362    union tex_tile_address addr;
1363    const float *out;
1364    int c;
1365 
1366    assert(width > 0);
1367    assert(height > 0);
1368    assert(depth > 0);
1369 
1370    sp_samp->nearest_texcoord_s(args->s, width,  args->offset[0], &x);
1371    sp_samp->nearest_texcoord_t(args->t, height, args->offset[1], &y);
1372    sp_samp->nearest_texcoord_p(args->p, depth,  args->offset[2], &z);
1373 
1374    addr.value = 0;
1375    addr.bits.level = args->level;
1376 
1377    out = get_texel_3d(sp_sview, sp_samp, addr, x, y, z);
1378    for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1379       rgba[TGSI_NUM_CHANNELS*c] = out[c];
1380 }
1381 
1382 
1383 static void
img_filter_1d_linear(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const struct img_filter_args * args,float * rgba)1384 img_filter_1d_linear(const struct sp_sampler_view *sp_sview,
1385                      const struct sp_sampler *sp_samp,
1386                      const struct img_filter_args *args,
1387                      float *rgba)
1388 {
1389    const struct pipe_resource *texture = sp_sview->base.texture;
1390    const int width = u_minify(texture->width0, args->level);
1391    int x0, x1;
1392    float xw; /* weights */
1393    union tex_tile_address addr;
1394    const float *tx0, *tx1;
1395    int c;
1396 
1397    assert(width > 0);
1398 
1399    addr.value = 0;
1400    addr.bits.level = args->level;
1401 
1402    sp_samp->linear_texcoord_s(args->s, width, args->offset[0], &x0, &x1, &xw);
1403 
1404    tx0 = get_texel_1d_array(sp_sview, sp_samp, addr, x0,
1405                             sp_sview->base.u.tex.first_layer);
1406    tx1 = get_texel_1d_array(sp_sview, sp_samp, addr, x1,
1407                             sp_sview->base.u.tex.first_layer);
1408 
1409    /* interpolate R, G, B, A */
1410    for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1411       rgba[TGSI_NUM_CHANNELS*c] = lerp(xw, tx0[c], tx1[c]);
1412 }
1413 
1414 
1415 static void
img_filter_1d_array_linear(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const struct img_filter_args * args,float * rgba)1416 img_filter_1d_array_linear(const struct sp_sampler_view *sp_sview,
1417                            const struct sp_sampler *sp_samp,
1418                            const struct img_filter_args *args,
1419                            float *rgba)
1420 {
1421    const struct pipe_resource *texture = sp_sview->base.texture;
1422    const int width = u_minify(texture->width0, args->level);
1423    const int layer = coord_to_layer(args->t, sp_sview->base.u.tex.first_layer,
1424                                     sp_sview->base.u.tex.last_layer);
1425    int x0, x1;
1426    float xw; /* weights */
1427    union tex_tile_address addr;
1428    const float *tx0, *tx1;
1429    int c;
1430 
1431    assert(width > 0);
1432 
1433    addr.value = 0;
1434    addr.bits.level = args->level;
1435 
1436    sp_samp->linear_texcoord_s(args->s, width, args->offset[0], &x0, &x1, &xw);
1437 
1438    tx0 = get_texel_1d_array(sp_sview, sp_samp, addr, x0, layer);
1439    tx1 = get_texel_1d_array(sp_sview, sp_samp, addr, x1, layer);
1440 
1441    /* interpolate R, G, B, A */
1442    for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1443       rgba[TGSI_NUM_CHANNELS*c] = lerp(xw, tx0[c], tx1[c]);
1444 }
1445 
1446 /*
1447  * Retrieve the gathered value, need to convert to the
1448  * TGSI expected interface, and take component select
1449  * and swizzling into account.
1450  */
1451 static float
get_gather_value(const struct sp_sampler_view * sp_sview,int chan_in,int comp_sel,const float * tx[4])1452 get_gather_value(const struct sp_sampler_view *sp_sview,
1453                  int chan_in, int comp_sel,
1454                  const float *tx[4])
1455 {
1456    int chan;
1457    unsigned swizzle;
1458 
1459    /*
1460     * softpipe samples in a different order
1461     * to TGSI expects, so we need to swizzle,
1462     * the samples into the correct slots.
1463     */
1464    switch (chan_in) {
1465    case 0:
1466       chan = 2;
1467       break;
1468    case 1:
1469       chan = 3;
1470       break;
1471    case 2:
1472       chan = 1;
1473       break;
1474    case 3:
1475       chan = 0;
1476       break;
1477    default:
1478       assert(0);
1479       return 0.0;
1480    }
1481 
1482    /* pick which component to use for the swizzle */
1483    switch (comp_sel) {
1484    case 0:
1485       swizzle = sp_sview->base.swizzle_r;
1486       break;
1487    case 1:
1488       swizzle = sp_sview->base.swizzle_g;
1489       break;
1490    case 2:
1491       swizzle = sp_sview->base.swizzle_b;
1492       break;
1493    case 3:
1494       swizzle = sp_sview->base.swizzle_a;
1495       break;
1496    default:
1497       assert(0);
1498       return 0.0;
1499    }
1500 
1501    /* get correct result using the channel and swizzle */
1502    switch (swizzle) {
1503    case PIPE_SWIZZLE_0:
1504       return 0.0;
1505    case PIPE_SWIZZLE_1:
1506       return 1.0;
1507    default:
1508       return tx[chan][swizzle];
1509    }
1510 }
1511 
1512 
1513 static void
img_filter_2d_linear(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const struct img_filter_args * args,float * rgba)1514 img_filter_2d_linear(const struct sp_sampler_view *sp_sview,
1515                      const struct sp_sampler *sp_samp,
1516                      const struct img_filter_args *args,
1517                      float *rgba)
1518 {
1519    const struct pipe_resource *texture = sp_sview->base.texture;
1520    const int width = u_minify(texture->width0, args->level);
1521    const int height = u_minify(texture->height0, args->level);
1522    int x0, y0, x1, y1;
1523    float xw, yw; /* weights */
1524    union tex_tile_address addr;
1525    const float *tx[4];
1526    int c;
1527 
1528    assert(width > 0);
1529    assert(height > 0);
1530 
1531    addr.value = 0;
1532    addr.bits.level = args->level;
1533    addr.bits.z = sp_sview->base.u.tex.first_layer;
1534 
1535    sp_samp->linear_texcoord_s(args->s, width,  args->offset[0], &x0, &x1, &xw);
1536    sp_samp->linear_texcoord_t(args->t, height, args->offset[1], &y0, &y1, &yw);
1537 
1538    tx[0] = get_texel_2d(sp_sview, sp_samp, addr, x0, y0);
1539    tx[1] = get_texel_2d(sp_sview, sp_samp, addr, x1, y0);
1540    tx[2] = get_texel_2d(sp_sview, sp_samp, addr, x0, y1);
1541    tx[3] = get_texel_2d(sp_sview, sp_samp, addr, x1, y1);
1542 
1543    if (args->gather_only) {
1544       for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1545          rgba[TGSI_NUM_CHANNELS*c] = get_gather_value(sp_sview, c,
1546                                                       args->gather_comp,
1547                                                       tx);
1548    } else {
1549       /* interpolate R, G, B, A */
1550       for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1551          rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw,
1552                                              tx[0][c], tx[1][c],
1553                                              tx[2][c], tx[3][c]);
1554    }
1555 }
1556 
1557 
1558 static void
img_filter_2d_array_linear(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const struct img_filter_args * args,float * rgba)1559 img_filter_2d_array_linear(const struct sp_sampler_view *sp_sview,
1560                            const struct sp_sampler *sp_samp,
1561                            const struct img_filter_args *args,
1562                            float *rgba)
1563 {
1564    const struct pipe_resource *texture = sp_sview->base.texture;
1565    const int width = u_minify(texture->width0, args->level);
1566    const int height = u_minify(texture->height0, args->level);
1567    const int layer = coord_to_layer(args->p, sp_sview->base.u.tex.first_layer,
1568                                     sp_sview->base.u.tex.last_layer);
1569    int x0, y0, x1, y1;
1570    float xw, yw; /* weights */
1571    union tex_tile_address addr;
1572    const float *tx[4];
1573    int c;
1574 
1575    assert(width > 0);
1576    assert(height > 0);
1577 
1578    addr.value = 0;
1579    addr.bits.level = args->level;
1580 
1581    sp_samp->linear_texcoord_s(args->s, width,  args->offset[0], &x0, &x1, &xw);
1582    sp_samp->linear_texcoord_t(args->t, height, args->offset[1], &y0, &y1, &yw);
1583 
1584    tx[0] = get_texel_2d_array(sp_sview, sp_samp, addr, x0, y0, layer);
1585    tx[1] = get_texel_2d_array(sp_sview, sp_samp, addr, x1, y0, layer);
1586    tx[2] = get_texel_2d_array(sp_sview, sp_samp, addr, x0, y1, layer);
1587    tx[3] = get_texel_2d_array(sp_sview, sp_samp, addr, x1, y1, layer);
1588 
1589    if (args->gather_only) {
1590       for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1591          rgba[TGSI_NUM_CHANNELS*c] = get_gather_value(sp_sview, c,
1592                                                       args->gather_comp,
1593                                                       tx);
1594    } else {
1595       /* interpolate R, G, B, A */
1596       for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1597          rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw,
1598                                              tx[0][c], tx[1][c],
1599                                              tx[2][c], tx[3][c]);
1600    }
1601 }
1602 
1603 
1604 static void
img_filter_cube_linear(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const struct img_filter_args * args,float * rgba)1605 img_filter_cube_linear(const struct sp_sampler_view *sp_sview,
1606                        const struct sp_sampler *sp_samp,
1607                        const struct img_filter_args *args,
1608                        float *rgba)
1609 {
1610    const struct pipe_resource *texture = sp_sview->base.texture;
1611    const int width = u_minify(texture->width0, args->level);
1612    const int height = u_minify(texture->height0, args->level);
1613    const int layer = sp_sview->base.u.tex.first_layer;
1614    int x0, y0, x1, y1;
1615    float xw, yw; /* weights */
1616    union tex_tile_address addr;
1617    const float *tx[4];
1618    float corner0[TGSI_QUAD_SIZE], corner1[TGSI_QUAD_SIZE],
1619          corner2[TGSI_QUAD_SIZE], corner3[TGSI_QUAD_SIZE];
1620    int c;
1621 
1622    assert(width > 0);
1623    assert(height > 0);
1624 
1625    addr.value = 0;
1626    addr.bits.level = args->level;
1627 
1628    /*
1629     * For seamless if LINEAR filtering is done within a miplevel,
1630     * always apply wrap mode CLAMP_TO_BORDER.
1631     */
1632    if (sp_samp->base.seamless_cube_map) {
1633       /* Note this is a bit overkill, actual clamping is not required */
1634       wrap_linear_clamp_to_border(args->s, width, args->offset[0], &x0, &x1, &xw);
1635       wrap_linear_clamp_to_border(args->t, height, args->offset[1], &y0, &y1, &yw);
1636    } else {
1637       /* Would probably make sense to ignore mode and just do edge clamp */
1638       sp_samp->linear_texcoord_s(args->s, width,  args->offset[0], &x0, &x1, &xw);
1639       sp_samp->linear_texcoord_t(args->t, height, args->offset[1], &y0, &y1, &yw);
1640    }
1641 
1642    if (sp_samp->base.seamless_cube_map) {
1643       tx[0] = get_texel_cube_seamless(sp_sview, addr, x0, y0, corner0, layer, args->face_id);
1644       tx[1] = get_texel_cube_seamless(sp_sview, addr, x1, y0, corner1, layer, args->face_id);
1645       tx[2] = get_texel_cube_seamless(sp_sview, addr, x0, y1, corner2, layer, args->face_id);
1646       tx[3] = get_texel_cube_seamless(sp_sview, addr, x1, y1, corner3, layer, args->face_id);
1647    } else {
1648       tx[0] = get_texel_cube_array(sp_sview, sp_samp, addr, x0, y0, layer + args->face_id);
1649       tx[1] = get_texel_cube_array(sp_sview, sp_samp, addr, x1, y0, layer + args->face_id);
1650       tx[2] = get_texel_cube_array(sp_sview, sp_samp, addr, x0, y1, layer + args->face_id);
1651       tx[3] = get_texel_cube_array(sp_sview, sp_samp, addr, x1, y1, layer + args->face_id);
1652    }
1653 
1654    if (args->gather_only) {
1655       for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1656          rgba[TGSI_NUM_CHANNELS*c] = get_gather_value(sp_sview, c,
1657                                                       args->gather_comp,
1658                                                       tx);
1659    } else {
1660       /* interpolate R, G, B, A */
1661       for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1662          rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw,
1663                                              tx[0][c], tx[1][c],
1664                                              tx[2][c], tx[3][c]);
1665    }
1666 }
1667 
1668 
1669 static void
img_filter_cube_array_linear(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const struct img_filter_args * args,float * rgba)1670 img_filter_cube_array_linear(const struct sp_sampler_view *sp_sview,
1671                              const struct sp_sampler *sp_samp,
1672                              const struct img_filter_args *args,
1673                              float *rgba)
1674 {
1675    const struct pipe_resource *texture = sp_sview->base.texture;
1676    const int width = u_minify(texture->width0, args->level);
1677    const int height = u_minify(texture->height0, args->level);
1678    const int layer =
1679       coord_to_layer(6 * args->p + sp_sview->base.u.tex.first_layer,
1680                      sp_sview->base.u.tex.first_layer,
1681                      sp_sview->base.u.tex.last_layer - 5);
1682    int x0, y0, x1, y1;
1683    float xw, yw; /* weights */
1684    union tex_tile_address addr;
1685    const float *tx[4];
1686    float corner0[TGSI_QUAD_SIZE], corner1[TGSI_QUAD_SIZE],
1687          corner2[TGSI_QUAD_SIZE], corner3[TGSI_QUAD_SIZE];
1688    int c;
1689 
1690    assert(width > 0);
1691    assert(height > 0);
1692 
1693    addr.value = 0;
1694    addr.bits.level = args->level;
1695 
1696    /*
1697     * For seamless if LINEAR filtering is done within a miplevel,
1698     * always apply wrap mode CLAMP_TO_BORDER.
1699     */
1700    if (sp_samp->base.seamless_cube_map) {
1701       /* Note this is a bit overkill, actual clamping is not required */
1702       wrap_linear_clamp_to_border(args->s, width, args->offset[0], &x0, &x1, &xw);
1703       wrap_linear_clamp_to_border(args->t, height, args->offset[1], &y0, &y1, &yw);
1704    } else {
1705       /* Would probably make sense to ignore mode and just do edge clamp */
1706       sp_samp->linear_texcoord_s(args->s, width,  args->offset[0], &x0, &x1, &xw);
1707       sp_samp->linear_texcoord_t(args->t, height, args->offset[1], &y0, &y1, &yw);
1708    }
1709 
1710    if (sp_samp->base.seamless_cube_map) {
1711       tx[0] = get_texel_cube_seamless(sp_sview, addr, x0, y0, corner0, layer, args->face_id);
1712       tx[1] = get_texel_cube_seamless(sp_sview, addr, x1, y0, corner1, layer, args->face_id);
1713       tx[2] = get_texel_cube_seamless(sp_sview, addr, x0, y1, corner2, layer, args->face_id);
1714       tx[3] = get_texel_cube_seamless(sp_sview, addr, x1, y1, corner3, layer, args->face_id);
1715    } else {
1716       tx[0] = get_texel_cube_array(sp_sview, sp_samp, addr, x0, y0, layer + args->face_id);
1717       tx[1] = get_texel_cube_array(sp_sview, sp_samp, addr, x1, y0, layer + args->face_id);
1718       tx[2] = get_texel_cube_array(sp_sview, sp_samp, addr, x0, y1, layer + args->face_id);
1719       tx[3] = get_texel_cube_array(sp_sview, sp_samp, addr, x1, y1, layer + args->face_id);
1720    }
1721 
1722    if (args->gather_only) {
1723       for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1724          rgba[TGSI_NUM_CHANNELS*c] = get_gather_value(sp_sview, c,
1725                                                       args->gather_comp,
1726                                                       tx);
1727    } else {
1728       /* interpolate R, G, B, A */
1729       for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1730          rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw,
1731                                              tx[0][c], tx[1][c],
1732                                              tx[2][c], tx[3][c]);
1733    }
1734 }
1735 
1736 static void
img_filter_3d_linear(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const struct img_filter_args * args,float * rgba)1737 img_filter_3d_linear(const struct sp_sampler_view *sp_sview,
1738                      const struct sp_sampler *sp_samp,
1739                      const struct img_filter_args *args,
1740                      float *rgba)
1741 {
1742    const struct pipe_resource *texture = sp_sview->base.texture;
1743    const int width = u_minify(texture->width0, args->level);
1744    const int height = u_minify(texture->height0, args->level);
1745    const int depth = u_minify(texture->depth0, args->level);
1746    int x0, x1, y0, y1, z0, z1;
1747    float xw, yw, zw; /* interpolation weights */
1748    union tex_tile_address addr;
1749    const float *tx00, *tx01, *tx02, *tx03, *tx10, *tx11, *tx12, *tx13;
1750    int c;
1751 
1752    addr.value = 0;
1753    addr.bits.level = args->level;
1754 
1755    assert(width > 0);
1756    assert(height > 0);
1757    assert(depth > 0);
1758 
1759    sp_samp->linear_texcoord_s(args->s, width,  args->offset[0], &x0, &x1, &xw);
1760    sp_samp->linear_texcoord_t(args->t, height, args->offset[1], &y0, &y1, &yw);
1761    sp_samp->linear_texcoord_p(args->p, depth,  args->offset[2], &z0, &z1, &zw);
1762 
1763    tx00 = get_texel_3d(sp_sview, sp_samp, addr, x0, y0, z0);
1764    tx01 = get_texel_3d(sp_sview, sp_samp, addr, x1, y0, z0);
1765    tx02 = get_texel_3d(sp_sview, sp_samp, addr, x0, y1, z0);
1766    tx03 = get_texel_3d(sp_sview, sp_samp, addr, x1, y1, z0);
1767 
1768    tx10 = get_texel_3d(sp_sview, sp_samp, addr, x0, y0, z1);
1769    tx11 = get_texel_3d(sp_sview, sp_samp, addr, x1, y0, z1);
1770    tx12 = get_texel_3d(sp_sview, sp_samp, addr, x0, y1, z1);
1771    tx13 = get_texel_3d(sp_sview, sp_samp, addr, x1, y1, z1);
1772 
1773       /* interpolate R, G, B, A */
1774    for (c = 0; c < TGSI_NUM_CHANNELS; c++)
1775       rgba[TGSI_NUM_CHANNELS*c] =  lerp_3d(xw, yw, zw,
1776                                            tx00[c], tx01[c],
1777                                            tx02[c], tx03[c],
1778                                            tx10[c], tx11[c],
1779                                            tx12[c], tx13[c]);
1780 }
1781 
1782 
1783 /* Calculate level of detail for every fragment,
1784  * with lambda already computed.
1785  * Note that lambda has already been biased by global LOD bias.
1786  * \param biased_lambda per-quad lambda.
1787  * \param lod_in per-fragment lod_bias or explicit_lod.
1788  * \param lod returns the per-fragment lod.
1789  */
1790 static inline void
compute_lod(const struct pipe_sampler_state * sampler,enum tgsi_sampler_control control,const float biased_lambda,const float lod_in[TGSI_QUAD_SIZE],float lod[TGSI_QUAD_SIZE])1791 compute_lod(const struct pipe_sampler_state *sampler,
1792             enum tgsi_sampler_control control,
1793             const float biased_lambda,
1794             const float lod_in[TGSI_QUAD_SIZE],
1795             float lod[TGSI_QUAD_SIZE])
1796 {
1797    const float min_lod = sampler->min_lod;
1798    const float max_lod = sampler->max_lod;
1799    uint i;
1800 
1801    switch (control) {
1802    case TGSI_SAMPLER_LOD_NONE:
1803    case TGSI_SAMPLER_LOD_ZERO:
1804    /* XXX FIXME */
1805    case TGSI_SAMPLER_DERIVS_EXPLICIT:
1806       lod[0] = lod[1] = lod[2] = lod[3] = CLAMP(biased_lambda, min_lod, max_lod);
1807       break;
1808    case TGSI_SAMPLER_LOD_BIAS:
1809       for (i = 0; i < TGSI_QUAD_SIZE; i++) {
1810          lod[i] = biased_lambda + lod_in[i];
1811          lod[i] = CLAMP(lod[i], min_lod, max_lod);
1812       }
1813       break;
1814    case TGSI_SAMPLER_LOD_EXPLICIT:
1815       for (i = 0; i < TGSI_QUAD_SIZE; i++) {
1816          lod[i] = CLAMP(lod_in[i], min_lod, max_lod);
1817       }
1818       break;
1819    default:
1820       assert(0);
1821       lod[0] = lod[1] = lod[2] = lod[3] = 0.0f;
1822    }
1823 }
1824 
1825 
1826 /* Calculate level of detail for every fragment. The computed value is not
1827  * clamped to lod_min and lod_max.
1828  * \param lod_in per-fragment lod_bias or explicit_lod.
1829  * \param lod results per-fragment lod.
1830  */
1831 static inline void
compute_lambda_lod_unclamped(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const float s[TGSI_QUAD_SIZE],const float t[TGSI_QUAD_SIZE],const float p[TGSI_QUAD_SIZE],const float lod_in[TGSI_QUAD_SIZE],enum tgsi_sampler_control control,float lod[TGSI_QUAD_SIZE])1832 compute_lambda_lod_unclamped(const struct sp_sampler_view *sp_sview,
1833                              const struct sp_sampler *sp_samp,
1834                              const float s[TGSI_QUAD_SIZE],
1835                              const float t[TGSI_QUAD_SIZE],
1836                              const float p[TGSI_QUAD_SIZE],
1837                              const float lod_in[TGSI_QUAD_SIZE],
1838                              enum tgsi_sampler_control control,
1839                              float lod[TGSI_QUAD_SIZE])
1840 {
1841    const struct pipe_sampler_state *sampler = &sp_samp->base;
1842    const float lod_bias = sampler->lod_bias;
1843    float lambda;
1844    uint i;
1845 
1846    switch (control) {
1847    case TGSI_SAMPLER_LOD_NONE:
1848       /* XXX FIXME */
1849    case TGSI_SAMPLER_DERIVS_EXPLICIT:
1850       lambda = sp_sview->compute_lambda(sp_sview, s, t, p) + lod_bias;
1851       lod[0] = lod[1] = lod[2] = lod[3] = lambda;
1852       break;
1853    case TGSI_SAMPLER_LOD_BIAS:
1854       lambda = sp_sview->compute_lambda(sp_sview, s, t, p) + lod_bias;
1855       for (i = 0; i < TGSI_QUAD_SIZE; i++) {
1856          lod[i] = lambda + lod_in[i];
1857       }
1858       break;
1859    case TGSI_SAMPLER_LOD_EXPLICIT:
1860       for (i = 0; i < TGSI_QUAD_SIZE; i++) {
1861          lod[i] = lod_in[i] + lod_bias;
1862       }
1863       break;
1864    case TGSI_SAMPLER_LOD_ZERO:
1865    case TGSI_SAMPLER_GATHER:
1866       lod[0] = lod[1] = lod[2] = lod[3] = lod_bias;
1867       break;
1868    default:
1869       assert(0);
1870       lod[0] = lod[1] = lod[2] = lod[3] = 0.0f;
1871    }
1872 }
1873 
1874 /* Calculate level of detail for every fragment.
1875  * \param lod_in per-fragment lod_bias or explicit_lod.
1876  * \param lod results per-fragment lod.
1877  */
1878 static inline void
compute_lambda_lod(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const float s[TGSI_QUAD_SIZE],const float t[TGSI_QUAD_SIZE],const float p[TGSI_QUAD_SIZE],const float lod_in[TGSI_QUAD_SIZE],enum tgsi_sampler_control control,float lod[TGSI_QUAD_SIZE])1879 compute_lambda_lod(const struct sp_sampler_view *sp_sview,
1880                    const struct sp_sampler *sp_samp,
1881                    const float s[TGSI_QUAD_SIZE],
1882                    const float t[TGSI_QUAD_SIZE],
1883                    const float p[TGSI_QUAD_SIZE],
1884                    const float lod_in[TGSI_QUAD_SIZE],
1885                    enum tgsi_sampler_control control,
1886                    float lod[TGSI_QUAD_SIZE])
1887 {
1888    const struct pipe_sampler_state *sampler = &sp_samp->base;
1889    const float min_lod = sampler->min_lod;
1890    const float max_lod = sampler->max_lod;
1891    int i;
1892 
1893    compute_lambda_lod_unclamped(sp_sview, sp_samp,
1894                                 s, t, p, lod_in, control, lod);
1895    for (i = 0; i < TGSI_QUAD_SIZE; i++) {
1896       lod[i] = CLAMP(lod[i], min_lod, max_lod);
1897    }
1898 }
1899 
1900 static inline unsigned
get_gather_component(const float lod_in[TGSI_QUAD_SIZE])1901 get_gather_component(const float lod_in[TGSI_QUAD_SIZE])
1902 {
1903    /* gather component is stored in lod_in slot as unsigned */
1904    return (*(unsigned int *)lod_in) & 0x3;
1905 }
1906 
1907 /**
1908  * Clamps given lod to both lod limits and mip level limits. Clamping to the
1909  * latter limits is done so that lod is relative to the first (base) level.
1910  */
1911 static void
clamp_lod(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const float lod[TGSI_QUAD_SIZE],float clamped[TGSI_QUAD_SIZE])1912 clamp_lod(const struct sp_sampler_view *sp_sview,
1913           const struct sp_sampler *sp_samp,
1914           const float lod[TGSI_QUAD_SIZE],
1915           float clamped[TGSI_QUAD_SIZE])
1916 {
1917    const float min_lod = sp_samp->base.min_lod;
1918    const float max_lod = sp_samp->base.max_lod;
1919    const float min_level = sp_sview->base.u.tex.first_level;
1920    const float max_level = sp_sview->base.u.tex.last_level;
1921    int i;
1922 
1923    for (i = 0; i < TGSI_QUAD_SIZE; i++) {
1924       float cl = lod[i];
1925 
1926       cl = CLAMP(cl, min_lod, max_lod);
1927       cl = CLAMP(cl, 0, max_level - min_level);
1928       clamped[i] = cl;
1929    }
1930 }
1931 
1932 /**
1933  * Get mip level relative to base level for linear mip filter
1934  */
1935 static void
mip_rel_level_linear(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const float lod[TGSI_QUAD_SIZE],float level[TGSI_QUAD_SIZE])1936 mip_rel_level_linear(const struct sp_sampler_view *sp_sview,
1937                      const struct sp_sampler *sp_samp,
1938                      const float lod[TGSI_QUAD_SIZE],
1939                      float level[TGSI_QUAD_SIZE])
1940 {
1941    clamp_lod(sp_sview, sp_samp, lod, level);
1942 }
1943 
1944 static void
mip_filter_linear(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,img_filter_func min_filter,img_filter_func mag_filter,const float s[TGSI_QUAD_SIZE],const float t[TGSI_QUAD_SIZE],const float p[TGSI_QUAD_SIZE],const float c0[TGSI_QUAD_SIZE],const float lod_in[TGSI_QUAD_SIZE],const struct filter_args * filt_args,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])1945 mip_filter_linear(const struct sp_sampler_view *sp_sview,
1946                   const struct sp_sampler *sp_samp,
1947                   img_filter_func min_filter,
1948                   img_filter_func mag_filter,
1949                   const float s[TGSI_QUAD_SIZE],
1950                   const float t[TGSI_QUAD_SIZE],
1951                   const float p[TGSI_QUAD_SIZE],
1952                   const float c0[TGSI_QUAD_SIZE],
1953                   const float lod_in[TGSI_QUAD_SIZE],
1954                   const struct filter_args *filt_args,
1955                   float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
1956 {
1957    const struct pipe_sampler_view *psview = &sp_sview->base;
1958    int j;
1959    float lod[TGSI_QUAD_SIZE];
1960    struct img_filter_args args;
1961 
1962    compute_lambda_lod(sp_sview, sp_samp, s, t, p, lod_in, filt_args->control, lod);
1963 
1964    args.offset = filt_args->offset;
1965    args.gather_only = filt_args->control == TGSI_SAMPLER_GATHER;
1966    args.gather_comp = get_gather_component(lod_in);
1967 
1968    for (j = 0; j < TGSI_QUAD_SIZE; j++) {
1969       const int level0 = psview->u.tex.first_level + (int)lod[j];
1970 
1971       args.s = s[j];
1972       args.t = t[j];
1973       args.p = p[j];
1974       args.face_id = filt_args->faces[j];
1975 
1976       if (lod[j] < 0.0) {
1977          args.level = psview->u.tex.first_level;
1978          mag_filter(sp_sview, sp_samp, &args, &rgba[0][j]);
1979       }
1980       else if (level0 >= (int) psview->u.tex.last_level) {
1981          args.level = psview->u.tex.last_level;
1982          min_filter(sp_sview, sp_samp, &args, &rgba[0][j]);
1983       }
1984       else {
1985          float levelBlend = frac(lod[j]);
1986          float rgbax[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE];
1987          int c;
1988 
1989          args.level = level0;
1990          min_filter(sp_sview, sp_samp, &args, &rgbax[0][0]);
1991          args.level = level0+1;
1992          min_filter(sp_sview, sp_samp, &args, &rgbax[0][1]);
1993 
1994          for (c = 0; c < 4; c++) {
1995             rgba[c][j] = lerp(levelBlend, rgbax[c][0], rgbax[c][1]);
1996          }
1997       }
1998    }
1999 
2000    if (DEBUG_TEX) {
2001       print_sample_4(__FUNCTION__, rgba);
2002    }
2003 }
2004 
2005 
2006 /**
2007  * Get mip level relative to base level for nearest mip filter
2008  */
2009 static void
mip_rel_level_nearest(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const float lod[TGSI_QUAD_SIZE],float level[TGSI_QUAD_SIZE])2010 mip_rel_level_nearest(const struct sp_sampler_view *sp_sview,
2011                       const struct sp_sampler *sp_samp,
2012                       const float lod[TGSI_QUAD_SIZE],
2013                       float level[TGSI_QUAD_SIZE])
2014 {
2015    int j;
2016 
2017    clamp_lod(sp_sview, sp_samp, lod, level);
2018    for (j = 0; j < TGSI_QUAD_SIZE; j++)
2019       /* TODO: It should rather be:
2020        * level[j] = ceil(level[j] + 0.5F) - 1.0F;
2021        */
2022       level[j] = (int)(level[j] + 0.5F);
2023 }
2024 
2025 /**
2026  * Compute nearest mipmap level from texcoords.
2027  * Then sample the texture level for four elements of a quad.
2028  * \param c0  the LOD bias factors, or absolute LODs (depending on control)
2029  */
2030 static void
mip_filter_nearest(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,img_filter_func min_filter,img_filter_func mag_filter,const float s[TGSI_QUAD_SIZE],const float t[TGSI_QUAD_SIZE],const float p[TGSI_QUAD_SIZE],const float c0[TGSI_QUAD_SIZE],const float lod_in[TGSI_QUAD_SIZE],const struct filter_args * filt_args,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])2031 mip_filter_nearest(const struct sp_sampler_view *sp_sview,
2032                    const struct sp_sampler *sp_samp,
2033                    img_filter_func min_filter,
2034                    img_filter_func mag_filter,
2035                    const float s[TGSI_QUAD_SIZE],
2036                    const float t[TGSI_QUAD_SIZE],
2037                    const float p[TGSI_QUAD_SIZE],
2038                    const float c0[TGSI_QUAD_SIZE],
2039                    const float lod_in[TGSI_QUAD_SIZE],
2040                    const struct filter_args *filt_args,
2041                    float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
2042 {
2043    const struct pipe_sampler_view *psview = &sp_sview->base;
2044    float lod[TGSI_QUAD_SIZE];
2045    int j;
2046    struct img_filter_args args;
2047 
2048    args.offset = filt_args->offset;
2049    args.gather_only = filt_args->control == TGSI_SAMPLER_GATHER;
2050    args.gather_comp = get_gather_component(lod_in);
2051 
2052    compute_lambda_lod(sp_sview, sp_samp, s, t, p, lod_in, filt_args->control, lod);
2053 
2054    for (j = 0; j < TGSI_QUAD_SIZE; j++) {
2055       args.s = s[j];
2056       args.t = t[j];
2057       args.p = p[j];
2058       args.face_id = filt_args->faces[j];
2059 
2060       if (lod[j] < 0.0) {
2061          args.level = psview->u.tex.first_level;
2062          mag_filter(sp_sview, sp_samp, &args, &rgba[0][j]);
2063       } else {
2064          const int level = psview->u.tex.first_level + (int)(lod[j] + 0.5F);
2065          args.level = MIN2(level, (int)psview->u.tex.last_level);
2066          min_filter(sp_sview, sp_samp, &args, &rgba[0][j]);
2067       }
2068    }
2069 
2070    if (DEBUG_TEX) {
2071       print_sample_4(__FUNCTION__, rgba);
2072    }
2073 }
2074 
2075 
2076 /**
2077  * Get mip level relative to base level for none mip filter
2078  */
2079 static void
mip_rel_level_none(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const float lod[TGSI_QUAD_SIZE],float level[TGSI_QUAD_SIZE])2080 mip_rel_level_none(const struct sp_sampler_view *sp_sview,
2081                    const struct sp_sampler *sp_samp,
2082                    const float lod[TGSI_QUAD_SIZE],
2083                    float level[TGSI_QUAD_SIZE])
2084 {
2085    int j;
2086 
2087    for (j = 0; j < TGSI_QUAD_SIZE; j++) {
2088       level[j] = 0;
2089    }
2090 }
2091 
2092 static void
mip_filter_none(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,img_filter_func min_filter,img_filter_func mag_filter,const float s[TGSI_QUAD_SIZE],const float t[TGSI_QUAD_SIZE],const float p[TGSI_QUAD_SIZE],const float c0[TGSI_QUAD_SIZE],const float lod_in[TGSI_QUAD_SIZE],const struct filter_args * filt_args,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])2093 mip_filter_none(const struct sp_sampler_view *sp_sview,
2094                 const struct sp_sampler *sp_samp,
2095                 img_filter_func min_filter,
2096                 img_filter_func mag_filter,
2097                 const float s[TGSI_QUAD_SIZE],
2098                 const float t[TGSI_QUAD_SIZE],
2099                 const float p[TGSI_QUAD_SIZE],
2100                 const float c0[TGSI_QUAD_SIZE],
2101                 const float lod_in[TGSI_QUAD_SIZE],
2102                 const struct filter_args *filt_args,
2103                 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
2104 {
2105    float lod[TGSI_QUAD_SIZE];
2106    int j;
2107    struct img_filter_args args;
2108 
2109    args.level = sp_sview->base.u.tex.first_level;
2110    args.offset = filt_args->offset;
2111    args.gather_only = filt_args->control == TGSI_SAMPLER_GATHER;
2112 
2113    compute_lambda_lod(sp_sview, sp_samp, s, t, p, lod_in, filt_args->control, lod);
2114 
2115    for (j = 0; j < TGSI_QUAD_SIZE; j++) {
2116       args.s = s[j];
2117       args.t = t[j];
2118       args.p = p[j];
2119       args.face_id = filt_args->faces[j];
2120       if (lod[j] < 0.0) {
2121          mag_filter(sp_sview, sp_samp, &args, &rgba[0][j]);
2122       }
2123       else {
2124          min_filter(sp_sview, sp_samp, &args, &rgba[0][j]);
2125       }
2126    }
2127 }
2128 
2129 
2130 /**
2131  * Get mip level relative to base level for none mip filter
2132  */
2133 static void
mip_rel_level_none_no_filter_select(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const float lod[TGSI_QUAD_SIZE],float level[TGSI_QUAD_SIZE])2134 mip_rel_level_none_no_filter_select(const struct sp_sampler_view *sp_sview,
2135                                     const struct sp_sampler *sp_samp,
2136                                     const float lod[TGSI_QUAD_SIZE],
2137                                     float level[TGSI_QUAD_SIZE])
2138 {
2139    mip_rel_level_none(sp_sview, sp_samp, lod, level);
2140 }
2141 
2142 static void
mip_filter_none_no_filter_select(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,img_filter_func min_filter,img_filter_func mag_filter,const float s[TGSI_QUAD_SIZE],const float t[TGSI_QUAD_SIZE],const float p[TGSI_QUAD_SIZE],const float c0[TGSI_QUAD_SIZE],const float lod_in[TGSI_QUAD_SIZE],const struct filter_args * filt_args,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])2143 mip_filter_none_no_filter_select(const struct sp_sampler_view *sp_sview,
2144                                  const struct sp_sampler *sp_samp,
2145                                  img_filter_func min_filter,
2146                                  img_filter_func mag_filter,
2147                                  const float s[TGSI_QUAD_SIZE],
2148                                  const float t[TGSI_QUAD_SIZE],
2149                                  const float p[TGSI_QUAD_SIZE],
2150                                  const float c0[TGSI_QUAD_SIZE],
2151                                  const float lod_in[TGSI_QUAD_SIZE],
2152                                  const struct filter_args *filt_args,
2153                                  float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
2154 {
2155    int j;
2156    struct img_filter_args args;
2157    args.level = sp_sview->base.u.tex.first_level;
2158    args.offset = filt_args->offset;
2159    args.gather_only = filt_args->control == TGSI_SAMPLER_GATHER;
2160    for (j = 0; j < TGSI_QUAD_SIZE; j++) {
2161       args.s = s[j];
2162       args.t = t[j];
2163       args.p = p[j];
2164       args.face_id = filt_args->faces[j];
2165       mag_filter(sp_sview, sp_samp, &args, &rgba[0][j]);
2166    }
2167 }
2168 
2169 
2170 /* For anisotropic filtering */
2171 #define WEIGHT_LUT_SIZE 1024
2172 
2173 static const float *weightLut = NULL;
2174 
2175 /**
2176  * Creates the look-up table used to speed-up EWA sampling
2177  */
2178 static void
create_filter_table(void)2179 create_filter_table(void)
2180 {
2181    unsigned i;
2182    if (!weightLut) {
2183       float *lut = (float *) MALLOC(WEIGHT_LUT_SIZE * sizeof(float));
2184 
2185       for (i = 0; i < WEIGHT_LUT_SIZE; ++i) {
2186          const float alpha = 2;
2187          const float r2 = (float) i / (float) (WEIGHT_LUT_SIZE - 1);
2188          const float weight = (float) exp(-alpha * r2);
2189          lut[i] = weight;
2190       }
2191       weightLut = lut;
2192    }
2193 }
2194 
2195 
2196 /**
2197  * Elliptical weighted average (EWA) filter for producing high quality
2198  * anisotropic filtered results.
2199  * Based on the Higher Quality Elliptical Weighted Average Filter
2200  * published by Paul S. Heckbert in his Master's Thesis
2201  * "Fundamentals of Texture Mapping and Image Warping" (1989)
2202  */
2203 static void
img_filter_2d_ewa(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,img_filter_func min_filter,img_filter_func mag_filter,const float s[TGSI_QUAD_SIZE],const float t[TGSI_QUAD_SIZE],const float p[TGSI_QUAD_SIZE],const uint faces[TGSI_QUAD_SIZE],const int8_t * offset,unsigned level,const float dudx,const float dvdx,const float dudy,const float dvdy,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])2204 img_filter_2d_ewa(const struct sp_sampler_view *sp_sview,
2205                   const struct sp_sampler *sp_samp,
2206                   img_filter_func min_filter,
2207                   img_filter_func mag_filter,
2208                   const float s[TGSI_QUAD_SIZE],
2209                   const float t[TGSI_QUAD_SIZE],
2210                   const float p[TGSI_QUAD_SIZE],
2211                   const uint faces[TGSI_QUAD_SIZE],
2212                   const int8_t *offset,
2213                   unsigned level,
2214                   const float dudx, const float dvdx,
2215                   const float dudy, const float dvdy,
2216                   float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
2217 {
2218    const struct pipe_resource *texture = sp_sview->base.texture;
2219 
2220    // ??? Won't the image filters blow up if level is negative?
2221    const unsigned level0 = level > 0 ? level : 0;
2222    const float scaling = 1.0f / (1 << level0);
2223    const int width = u_minify(texture->width0, level0);
2224    const int height = u_minify(texture->height0, level0);
2225    struct img_filter_args args;
2226    const float ux = dudx * scaling;
2227    const float vx = dvdx * scaling;
2228    const float uy = dudy * scaling;
2229    const float vy = dvdy * scaling;
2230 
2231    /* compute ellipse coefficients to bound the region:
2232     * A*x*x + B*x*y + C*y*y = F.
2233     */
2234    float A = vx*vx+vy*vy+1;
2235    float B = -2*(ux*vx+uy*vy);
2236    float C = ux*ux+uy*uy+1;
2237    float F = A*C-B*B/4.0f;
2238 
2239    /* check if it is an ellipse */
2240    /* assert(F > 0.0); */
2241 
2242    /* Compute the ellipse's (u,v) bounding box in texture space */
2243    const float d = -B*B+4.0f*C*A;
2244    const float box_u = 2.0f / d * sqrtf(d*C*F); /* box_u -> half of bbox with   */
2245    const float box_v = 2.0f / d * sqrtf(A*d*F); /* box_v -> half of bbox height */
2246 
2247    float rgba_temp[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE];
2248    float s_buffer[TGSI_QUAD_SIZE];
2249    float t_buffer[TGSI_QUAD_SIZE];
2250    float weight_buffer[TGSI_QUAD_SIZE];
2251    int j;
2252 
2253    /* For each quad, the du and dx values are the same and so the ellipse is
2254     * also the same. Note that texel/image access can only be performed using
2255     * a quad, i.e. it is not possible to get the pixel value for a single
2256     * tex coord. In order to have a better performance, the access is buffered
2257     * using the s_buffer/t_buffer and weight_buffer. Only when the buffer is
2258     * full, then the pixel values are read from the image.
2259     */
2260    const float ddq = 2 * A;
2261 
2262    /* Scale ellipse formula to directly index the Filter Lookup Table.
2263     * i.e. scale so that F = WEIGHT_LUT_SIZE-1
2264     */
2265    const double formScale = (double) (WEIGHT_LUT_SIZE - 1) / F;
2266    A *= formScale;
2267    B *= formScale;
2268    C *= formScale;
2269    /* F *= formScale; */ /* no need to scale F as we don't use it below here */
2270 
2271    args.level = level;
2272    args.offset = offset;
2273 
2274    for (j = 0; j < TGSI_QUAD_SIZE; j++) {
2275       /* Heckbert MS thesis, p. 59; scan over the bounding box of the ellipse
2276        * and incrementally update the value of Ax^2+Bxy*Cy^2; when this
2277        * value, q, is less than F, we're inside the ellipse
2278        */
2279       const float tex_u = -0.5F + s[j] * texture->width0 * scaling;
2280       const float tex_v = -0.5F + t[j] * texture->height0 * scaling;
2281 
2282       const int u0 = (int) floorf(tex_u - box_u);
2283       const int u1 = (int) ceilf(tex_u + box_u);
2284       const int v0 = (int) floorf(tex_v - box_v);
2285       const int v1 = (int) ceilf(tex_v + box_v);
2286       const float U = u0 - tex_u;
2287 
2288       float num[4] = {0.0F, 0.0F, 0.0F, 0.0F};
2289       unsigned buffer_next = 0;
2290       float den = 0;
2291       int v;
2292       args.face_id = faces[j];
2293 
2294       for (v = v0; v <= v1; ++v) {
2295          const float V = v - tex_v;
2296          float dq = A * (2 * U + 1) + B * V;
2297          float q = (C * V + B * U) * V + A * U * U;
2298 
2299          int u;
2300          for (u = u0; u <= u1; ++u) {
2301             /* Note that the ellipse has been pre-scaled so F =
2302              * WEIGHT_LUT_SIZE - 1
2303              */
2304             if (q < WEIGHT_LUT_SIZE) {
2305                /* as a LUT is used, q must never be negative;
2306                 * should not happen, though
2307                 */
2308                const int qClamped = q >= 0.0F ? q : 0;
2309                const float weight = weightLut[qClamped];
2310 
2311                weight_buffer[buffer_next] = weight;
2312                s_buffer[buffer_next] = u / ((float) width);
2313                t_buffer[buffer_next] = v / ((float) height);
2314 
2315                buffer_next++;
2316                if (buffer_next == TGSI_QUAD_SIZE) {
2317                   /* 4 texel coords are in the buffer -> read it now */
2318                   unsigned jj;
2319                   /* it is assumed that samp->min_img_filter is set to
2320                    * img_filter_2d_nearest or one of the
2321                    * accelerated img_filter_2d_nearest_XXX functions.
2322                    */
2323                   for (jj = 0; jj < buffer_next; jj++) {
2324                      args.s = s_buffer[jj];
2325                      args.t = t_buffer[jj];
2326                      args.p = p[jj];
2327                      min_filter(sp_sview, sp_samp, &args, &rgba_temp[0][jj]);
2328                      num[0] += weight_buffer[jj] * rgba_temp[0][jj];
2329                      num[1] += weight_buffer[jj] * rgba_temp[1][jj];
2330                      num[2] += weight_buffer[jj] * rgba_temp[2][jj];
2331                      num[3] += weight_buffer[jj] * rgba_temp[3][jj];
2332                   }
2333 
2334                   buffer_next = 0;
2335                }
2336 
2337                den += weight;
2338             }
2339             q += dq;
2340             dq += ddq;
2341          }
2342       }
2343 
2344       /* if the tex coord buffer contains unread values, we will read
2345        * them now.
2346        */
2347       if (buffer_next > 0) {
2348          unsigned jj;
2349          /* it is assumed that samp->min_img_filter is set to
2350           * img_filter_2d_nearest or one of the
2351           * accelerated img_filter_2d_nearest_XXX functions.
2352           */
2353          for (jj = 0; jj < buffer_next; jj++) {
2354             args.s = s_buffer[jj];
2355             args.t = t_buffer[jj];
2356             args.p = p[jj];
2357             min_filter(sp_sview, sp_samp, &args, &rgba_temp[0][jj]);
2358             num[0] += weight_buffer[jj] * rgba_temp[0][jj];
2359             num[1] += weight_buffer[jj] * rgba_temp[1][jj];
2360             num[2] += weight_buffer[jj] * rgba_temp[2][jj];
2361             num[3] += weight_buffer[jj] * rgba_temp[3][jj];
2362          }
2363       }
2364 
2365       if (den <= 0.0F) {
2366          /* Reaching this place would mean that no pixels intersected
2367           * the ellipse.  This should never happen because the filter
2368           * we use always intersects at least one pixel.
2369           */
2370 
2371          /*rgba[0]=0;
2372          rgba[1]=0;
2373          rgba[2]=0;
2374          rgba[3]=0;*/
2375          /* not enough pixels in resampling, resort to direct interpolation */
2376          args.s = s[j];
2377          args.t = t[j];
2378          args.p = p[j];
2379          min_filter(sp_sview, sp_samp, &args, &rgba_temp[0][j]);
2380          den = 1;
2381          num[0] = rgba_temp[0][j];
2382          num[1] = rgba_temp[1][j];
2383          num[2] = rgba_temp[2][j];
2384          num[3] = rgba_temp[3][j];
2385       }
2386 
2387       rgba[0][j] = num[0] / den;
2388       rgba[1][j] = num[1] / den;
2389       rgba[2][j] = num[2] / den;
2390       rgba[3][j] = num[3] / den;
2391    }
2392 }
2393 
2394 
2395 /**
2396  * Get mip level relative to base level for linear mip filter
2397  */
2398 static void
mip_rel_level_linear_aniso(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const float lod[TGSI_QUAD_SIZE],float level[TGSI_QUAD_SIZE])2399 mip_rel_level_linear_aniso(const struct sp_sampler_view *sp_sview,
2400                            const struct sp_sampler *sp_samp,
2401                            const float lod[TGSI_QUAD_SIZE],
2402                            float level[TGSI_QUAD_SIZE])
2403 {
2404    mip_rel_level_linear(sp_sview, sp_samp, lod, level);
2405 }
2406 
2407 /**
2408  * Sample 2D texture using an anisotropic filter.
2409  */
2410 static void
mip_filter_linear_aniso(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,img_filter_func min_filter,img_filter_func mag_filter,const float s[TGSI_QUAD_SIZE],const float t[TGSI_QUAD_SIZE],const float p[TGSI_QUAD_SIZE],const float c0[TGSI_QUAD_SIZE],const float lod_in[TGSI_QUAD_SIZE],const struct filter_args * filt_args,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])2411 mip_filter_linear_aniso(const struct sp_sampler_view *sp_sview,
2412                         const struct sp_sampler *sp_samp,
2413                         img_filter_func min_filter,
2414                         img_filter_func mag_filter,
2415                         const float s[TGSI_QUAD_SIZE],
2416                         const float t[TGSI_QUAD_SIZE],
2417                         const float p[TGSI_QUAD_SIZE],
2418                         const float c0[TGSI_QUAD_SIZE],
2419                         const float lod_in[TGSI_QUAD_SIZE],
2420                         const struct filter_args *filt_args,
2421                         float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
2422 {
2423    const struct pipe_resource *texture = sp_sview->base.texture;
2424    const struct pipe_sampler_view *psview = &sp_sview->base;
2425    int level0;
2426    float lambda;
2427    float lod[TGSI_QUAD_SIZE];
2428 
2429    const float s_to_u = u_minify(texture->width0, psview->u.tex.first_level);
2430    const float t_to_v = u_minify(texture->height0, psview->u.tex.first_level);
2431    const float dudx = (s[QUAD_BOTTOM_RIGHT] - s[QUAD_BOTTOM_LEFT]) * s_to_u;
2432    const float dudy = (s[QUAD_TOP_LEFT]     - s[QUAD_BOTTOM_LEFT]) * s_to_u;
2433    const float dvdx = (t[QUAD_BOTTOM_RIGHT] - t[QUAD_BOTTOM_LEFT]) * t_to_v;
2434    const float dvdy = (t[QUAD_TOP_LEFT]     - t[QUAD_BOTTOM_LEFT]) * t_to_v;
2435    struct img_filter_args args;
2436 
2437    args.offset = filt_args->offset;
2438 
2439    if (filt_args->control == TGSI_SAMPLER_LOD_BIAS ||
2440        filt_args->control == TGSI_SAMPLER_LOD_NONE ||
2441        /* XXX FIXME */
2442        filt_args->control == TGSI_SAMPLER_DERIVS_EXPLICIT) {
2443       /* note: instead of working with Px and Py, we will use the
2444        * squared length instead, to avoid sqrt.
2445        */
2446       const float Px2 = dudx * dudx + dvdx * dvdx;
2447       const float Py2 = dudy * dudy + dvdy * dvdy;
2448 
2449       float Pmax2;
2450       float Pmin2;
2451       float e;
2452       const float maxEccentricity = sp_samp->base.max_anisotropy * sp_samp->base.max_anisotropy;
2453 
2454       if (Px2 < Py2) {
2455          Pmax2 = Py2;
2456          Pmin2 = Px2;
2457       }
2458       else {
2459          Pmax2 = Px2;
2460          Pmin2 = Py2;
2461       }
2462 
2463       /* if the eccentricity of the ellipse is too big, scale up the shorter
2464        * of the two vectors to limit the maximum amount of work per pixel
2465        */
2466       e = Pmax2 / Pmin2;
2467       if (e > maxEccentricity) {
2468          /* float s=e / maxEccentricity;
2469             minor[0] *= s;
2470             minor[1] *= s;
2471             Pmin2 *= s; */
2472          Pmin2 = Pmax2 / maxEccentricity;
2473       }
2474 
2475       /* note: we need to have Pmin=sqrt(Pmin2) here, but we can avoid
2476        * this since 0.5*log(x) = log(sqrt(x))
2477        */
2478       lambda = 0.5F * util_fast_log2(Pmin2) + sp_samp->base.lod_bias;
2479       compute_lod(&sp_samp->base, filt_args->control, lambda, lod_in, lod);
2480    }
2481    else {
2482       assert(filt_args->control == TGSI_SAMPLER_LOD_EXPLICIT ||
2483              filt_args->control == TGSI_SAMPLER_LOD_ZERO);
2484       compute_lod(&sp_samp->base, filt_args->control, sp_samp->base.lod_bias, lod_in, lod);
2485    }
2486 
2487    /* XXX: Take into account all lod values.
2488     */
2489    lambda = lod[0];
2490    level0 = psview->u.tex.first_level + (int)lambda;
2491 
2492    /* If the ellipse covers the whole image, we can
2493     * simply return the average of the whole image.
2494     */
2495    if (level0 >= (int) psview->u.tex.last_level) {
2496       int j;
2497       for (j = 0; j < TGSI_QUAD_SIZE; j++) {
2498          args.s = s[j];
2499          args.t = t[j];
2500          args.p = p[j];
2501          args.level = psview->u.tex.last_level;
2502          args.face_id = filt_args->faces[j];
2503          /*
2504           * XXX: we overwrote any linear filter with nearest, so this
2505           * isn't right (albeit if last level is 1x1 and no border it
2506           * will work just the same).
2507           */
2508          min_filter(sp_sview, sp_samp, &args, &rgba[0][j]);
2509       }
2510    }
2511    else {
2512       /* don't bother interpolating between multiple LODs; it doesn't
2513        * seem to be worth the extra running time.
2514        */
2515       img_filter_2d_ewa(sp_sview, sp_samp, min_filter, mag_filter,
2516                         s, t, p, filt_args->faces, filt_args->offset,
2517                         level0, dudx, dvdx, dudy, dvdy, rgba);
2518    }
2519 
2520    if (DEBUG_TEX) {
2521       print_sample_4(__FUNCTION__, rgba);
2522    }
2523 }
2524 
2525 /**
2526  * Get mip level relative to base level for linear mip filter
2527  */
2528 static void
mip_rel_level_linear_2d_linear_repeat_POT(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const float lod[TGSI_QUAD_SIZE],float level[TGSI_QUAD_SIZE])2529 mip_rel_level_linear_2d_linear_repeat_POT(
2530    const struct sp_sampler_view *sp_sview,
2531    const struct sp_sampler *sp_samp,
2532    const float lod[TGSI_QUAD_SIZE],
2533    float level[TGSI_QUAD_SIZE])
2534 {
2535    mip_rel_level_linear(sp_sview, sp_samp, lod, level);
2536 }
2537 
2538 /**
2539  * Specialized version of mip_filter_linear with hard-wired calls to
2540  * 2d lambda calculation and 2d_linear_repeat_POT img filters.
2541  */
2542 static void
mip_filter_linear_2d_linear_repeat_POT(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,img_filter_func min_filter,img_filter_func mag_filter,const float s[TGSI_QUAD_SIZE],const float t[TGSI_QUAD_SIZE],const float p[TGSI_QUAD_SIZE],const float c0[TGSI_QUAD_SIZE],const float lod_in[TGSI_QUAD_SIZE],const struct filter_args * filt_args,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])2543 mip_filter_linear_2d_linear_repeat_POT(
2544    const struct sp_sampler_view *sp_sview,
2545    const struct sp_sampler *sp_samp,
2546    img_filter_func min_filter,
2547    img_filter_func mag_filter,
2548    const float s[TGSI_QUAD_SIZE],
2549    const float t[TGSI_QUAD_SIZE],
2550    const float p[TGSI_QUAD_SIZE],
2551    const float c0[TGSI_QUAD_SIZE],
2552    const float lod_in[TGSI_QUAD_SIZE],
2553    const struct filter_args *filt_args,
2554    float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
2555 {
2556    const struct pipe_sampler_view *psview = &sp_sview->base;
2557    int j;
2558    float lod[TGSI_QUAD_SIZE];
2559 
2560    compute_lambda_lod(sp_sview, sp_samp, s, t, p, lod_in, filt_args->control, lod);
2561 
2562    for (j = 0; j < TGSI_QUAD_SIZE; j++) {
2563       const int level0 = psview->u.tex.first_level + (int)lod[j];
2564       struct img_filter_args args;
2565       /* Catches both negative and large values of level0:
2566        */
2567       args.s = s[j];
2568       args.t = t[j];
2569       args.p = p[j];
2570       args.face_id = filt_args->faces[j];
2571       args.offset = filt_args->offset;
2572       args.gather_only = filt_args->control == TGSI_SAMPLER_GATHER;
2573       if ((unsigned)level0 >= psview->u.tex.last_level) {
2574          if (level0 < 0)
2575             args.level = psview->u.tex.first_level;
2576          else
2577             args.level = psview->u.tex.last_level;
2578          img_filter_2d_linear_repeat_POT(sp_sview, sp_samp, &args,
2579                                          &rgba[0][j]);
2580 
2581       }
2582       else {
2583          const float levelBlend = frac(lod[j]);
2584          float rgbax[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE];
2585          int c;
2586 
2587          args.level = level0;
2588          img_filter_2d_linear_repeat_POT(sp_sview, sp_samp, &args, &rgbax[0][0]);
2589          args.level = level0+1;
2590          img_filter_2d_linear_repeat_POT(sp_sview, sp_samp, &args, &rgbax[0][1]);
2591 
2592          for (c = 0; c < TGSI_NUM_CHANNELS; c++)
2593             rgba[c][j] = lerp(levelBlend, rgbax[c][0], rgbax[c][1]);
2594       }
2595    }
2596 
2597    if (DEBUG_TEX) {
2598       print_sample_4(__FUNCTION__, rgba);
2599    }
2600 }
2601 
2602 static const struct sp_filter_funcs funcs_linear = {
2603    mip_rel_level_linear,
2604    mip_filter_linear
2605 };
2606 
2607 static const struct sp_filter_funcs funcs_nearest = {
2608    mip_rel_level_nearest,
2609    mip_filter_nearest
2610 };
2611 
2612 static const struct sp_filter_funcs funcs_none = {
2613    mip_rel_level_none,
2614    mip_filter_none
2615 };
2616 
2617 static const struct sp_filter_funcs funcs_none_no_filter_select = {
2618    mip_rel_level_none_no_filter_select,
2619    mip_filter_none_no_filter_select
2620 };
2621 
2622 static const struct sp_filter_funcs funcs_linear_aniso = {
2623    mip_rel_level_linear_aniso,
2624    mip_filter_linear_aniso
2625 };
2626 
2627 static const struct sp_filter_funcs funcs_linear_2d_linear_repeat_POT = {
2628    mip_rel_level_linear_2d_linear_repeat_POT,
2629    mip_filter_linear_2d_linear_repeat_POT
2630 };
2631 
2632 /**
2633  * Do shadow/depth comparisons.
2634  */
2635 static void
sample_compare(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const float s[TGSI_QUAD_SIZE],const float t[TGSI_QUAD_SIZE],const float p[TGSI_QUAD_SIZE],const float c0[TGSI_QUAD_SIZE],const float c1[TGSI_QUAD_SIZE],enum tgsi_sampler_control control,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])2636 sample_compare(const struct sp_sampler_view *sp_sview,
2637                const struct sp_sampler *sp_samp,
2638                const float s[TGSI_QUAD_SIZE],
2639                const float t[TGSI_QUAD_SIZE],
2640                const float p[TGSI_QUAD_SIZE],
2641                const float c0[TGSI_QUAD_SIZE],
2642                const float c1[TGSI_QUAD_SIZE],
2643                enum tgsi_sampler_control control,
2644                float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
2645 {
2646    const struct pipe_sampler_state *sampler = &sp_samp->base;
2647    int j, v;
2648    int k[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE];
2649    float pc[4];
2650    const struct util_format_description *format_desc =
2651       util_format_description(sp_sview->base.format);
2652    /* not entirely sure we couldn't end up with non-valid swizzle here */
2653    const unsigned chan_type =
2654       format_desc->swizzle[0] <= PIPE_SWIZZLE_W ?
2655       format_desc->channel[format_desc->swizzle[0]].type :
2656       UTIL_FORMAT_TYPE_FLOAT;
2657    const bool is_gather = (control == TGSI_SAMPLER_GATHER);
2658 
2659    /**
2660     * Compare texcoord 'p' (aka R) against texture value 'rgba[0]'
2661     * for 2D Array texture we need to use the 'c0' (aka Q).
2662     * When we sampled the depth texture, the depth value was put into all
2663     * RGBA channels.  We look at the red channel here.
2664     */
2665 
2666    if (sp_sview->base.target == PIPE_TEXTURE_2D_ARRAY ||
2667        sp_sview->base.target == PIPE_TEXTURE_CUBE) {
2668       pc[0] = c0[0];
2669       pc[1] = c0[1];
2670       pc[2] = c0[2];
2671       pc[3] = c0[3];
2672    } else if (sp_sview->base.target == PIPE_TEXTURE_CUBE_ARRAY) {
2673       pc[0] = c1[0];
2674       pc[1] = c1[1];
2675       pc[2] = c1[2];
2676       pc[3] = c1[3];
2677    } else {
2678       pc[0] = p[0];
2679       pc[1] = p[1];
2680       pc[2] = p[2];
2681       pc[3] = p[3];
2682    }
2683 
2684    if (chan_type != UTIL_FORMAT_TYPE_FLOAT) {
2685       /*
2686        * clamping is a result of conversion to texture format, hence
2687        * doesn't happen with floats. Technically also should do comparison
2688        * in texture format (quantization!).
2689        */
2690       pc[0] = CLAMP(pc[0], 0.0F, 1.0F);
2691       pc[1] = CLAMP(pc[1], 0.0F, 1.0F);
2692       pc[2] = CLAMP(pc[2], 0.0F, 1.0F);
2693       pc[3] = CLAMP(pc[3], 0.0F, 1.0F);
2694    }
2695 
2696    for (v = 0; v < (is_gather ? TGSI_NUM_CHANNELS : 1); v++) {
2697       /* compare four texcoords vs. four texture samples */
2698       switch (sampler->compare_func) {
2699       case PIPE_FUNC_LESS:
2700          k[v][0] = pc[0] < rgba[v][0];
2701          k[v][1] = pc[1] < rgba[v][1];
2702          k[v][2] = pc[2] < rgba[v][2];
2703          k[v][3] = pc[3] < rgba[v][3];
2704          break;
2705       case PIPE_FUNC_LEQUAL:
2706          k[v][0] = pc[0] <= rgba[v][0];
2707          k[v][1] = pc[1] <= rgba[v][1];
2708          k[v][2] = pc[2] <= rgba[v][2];
2709          k[v][3] = pc[3] <= rgba[v][3];
2710          break;
2711       case PIPE_FUNC_GREATER:
2712          k[v][0] = pc[0] > rgba[v][0];
2713          k[v][1] = pc[1] > rgba[v][1];
2714          k[v][2] = pc[2] > rgba[v][2];
2715          k[v][3] = pc[3] > rgba[v][3];
2716          break;
2717       case PIPE_FUNC_GEQUAL:
2718          k[v][0] = pc[0] >= rgba[v][0];
2719          k[v][1] = pc[1] >= rgba[v][1];
2720          k[v][2] = pc[2] >= rgba[v][2];
2721          k[v][3] = pc[3] >= rgba[v][3];
2722          break;
2723       case PIPE_FUNC_EQUAL:
2724          k[v][0] = pc[0] == rgba[v][0];
2725          k[v][1] = pc[1] == rgba[v][1];
2726          k[v][2] = pc[2] == rgba[v][2];
2727          k[v][3] = pc[3] == rgba[v][3];
2728          break;
2729       case PIPE_FUNC_NOTEQUAL:
2730          k[v][0] = pc[0] != rgba[v][0];
2731          k[v][1] = pc[1] != rgba[v][1];
2732          k[v][2] = pc[2] != rgba[v][2];
2733          k[v][3] = pc[3] != rgba[v][3];
2734          break;
2735       case PIPE_FUNC_ALWAYS:
2736          k[v][0] = k[v][1] = k[v][2] = k[v][3] = 1;
2737          break;
2738       case PIPE_FUNC_NEVER:
2739          k[v][0] = k[v][1] = k[v][2] = k[v][3] = 0;
2740          break;
2741       default:
2742          k[v][0] = k[v][1] = k[v][2] = k[v][3] = 0;
2743          assert(0);
2744          break;
2745       }
2746    }
2747 
2748    if (is_gather) {
2749       for (j = 0; j < TGSI_QUAD_SIZE; j++) {
2750          for (v = 0; v < TGSI_NUM_CHANNELS; v++) {
2751             rgba[v][j] = k[v][j];
2752          }
2753       }
2754    } else {
2755       for (j = 0; j < TGSI_QUAD_SIZE; j++) {
2756          rgba[0][j] = k[0][j];
2757          rgba[1][j] = k[0][j];
2758          rgba[2][j] = k[0][j];
2759          rgba[3][j] = 1.0F;
2760       }
2761    }
2762 }
2763 
2764 static void
do_swizzling(const struct pipe_sampler_view * sview,float in[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],float out[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])2765 do_swizzling(const struct pipe_sampler_view *sview,
2766              float in[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
2767              float out[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
2768 {
2769    int j;
2770    const unsigned swizzle_r = sview->swizzle_r;
2771    const unsigned swizzle_g = sview->swizzle_g;
2772    const unsigned swizzle_b = sview->swizzle_b;
2773    const unsigned swizzle_a = sview->swizzle_a;
2774 
2775    switch (swizzle_r) {
2776    case PIPE_SWIZZLE_0:
2777       for (j = 0; j < 4; j++)
2778          out[0][j] = 0.0f;
2779       break;
2780    case PIPE_SWIZZLE_1:
2781       for (j = 0; j < 4; j++)
2782          out[0][j] = 1.0f;
2783       break;
2784    default:
2785       assert(swizzle_r < 4);
2786       for (j = 0; j < 4; j++)
2787          out[0][j] = in[swizzle_r][j];
2788    }
2789 
2790    switch (swizzle_g) {
2791    case PIPE_SWIZZLE_0:
2792       for (j = 0; j < 4; j++)
2793          out[1][j] = 0.0f;
2794       break;
2795    case PIPE_SWIZZLE_1:
2796       for (j = 0; j < 4; j++)
2797          out[1][j] = 1.0f;
2798       break;
2799    default:
2800       assert(swizzle_g < 4);
2801       for (j = 0; j < 4; j++)
2802          out[1][j] = in[swizzle_g][j];
2803    }
2804 
2805    switch (swizzle_b) {
2806    case PIPE_SWIZZLE_0:
2807       for (j = 0; j < 4; j++)
2808          out[2][j] = 0.0f;
2809       break;
2810    case PIPE_SWIZZLE_1:
2811       for (j = 0; j < 4; j++)
2812          out[2][j] = 1.0f;
2813       break;
2814    default:
2815       assert(swizzle_b < 4);
2816       for (j = 0; j < 4; j++)
2817          out[2][j] = in[swizzle_b][j];
2818    }
2819 
2820    switch (swizzle_a) {
2821    case PIPE_SWIZZLE_0:
2822       for (j = 0; j < 4; j++)
2823          out[3][j] = 0.0f;
2824       break;
2825    case PIPE_SWIZZLE_1:
2826       for (j = 0; j < 4; j++)
2827          out[3][j] = 1.0f;
2828       break;
2829    default:
2830       assert(swizzle_a < 4);
2831       for (j = 0; j < 4; j++)
2832          out[3][j] = in[swizzle_a][j];
2833    }
2834 }
2835 
2836 
2837 static wrap_nearest_func
get_nearest_unorm_wrap(unsigned mode)2838 get_nearest_unorm_wrap(unsigned mode)
2839 {
2840    switch (mode) {
2841    case PIPE_TEX_WRAP_CLAMP:
2842       return wrap_nearest_unorm_clamp;
2843    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
2844       return wrap_nearest_unorm_clamp_to_edge;
2845    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
2846       return wrap_nearest_unorm_clamp_to_border;
2847    default:
2848       debug_printf("illegal wrap mode %d with non-normalized coords\n", mode);
2849       return wrap_nearest_unorm_clamp;
2850    }
2851 }
2852 
2853 
2854 static wrap_nearest_func
get_nearest_wrap(unsigned mode)2855 get_nearest_wrap(unsigned mode)
2856 {
2857    switch (mode) {
2858    case PIPE_TEX_WRAP_REPEAT:
2859       return wrap_nearest_repeat;
2860    case PIPE_TEX_WRAP_CLAMP:
2861       return wrap_nearest_clamp;
2862    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
2863       return wrap_nearest_clamp_to_edge;
2864    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
2865       return wrap_nearest_clamp_to_border;
2866    case PIPE_TEX_WRAP_MIRROR_REPEAT:
2867       return wrap_nearest_mirror_repeat;
2868    case PIPE_TEX_WRAP_MIRROR_CLAMP:
2869       return wrap_nearest_mirror_clamp;
2870    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
2871       return wrap_nearest_mirror_clamp_to_edge;
2872    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
2873       return wrap_nearest_mirror_clamp_to_border;
2874    default:
2875       assert(0);
2876       return wrap_nearest_repeat;
2877    }
2878 }
2879 
2880 
2881 static wrap_linear_func
get_linear_unorm_wrap(unsigned mode)2882 get_linear_unorm_wrap(unsigned mode)
2883 {
2884    switch (mode) {
2885    case PIPE_TEX_WRAP_CLAMP:
2886       return wrap_linear_unorm_clamp;
2887    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
2888       return wrap_linear_unorm_clamp_to_edge;
2889    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
2890       return wrap_linear_unorm_clamp_to_border;
2891    default:
2892       debug_printf("illegal wrap mode %d with non-normalized coords\n", mode);
2893       return wrap_linear_unorm_clamp;
2894    }
2895 }
2896 
2897 
2898 static wrap_linear_func
get_linear_wrap(unsigned mode)2899 get_linear_wrap(unsigned mode)
2900 {
2901    switch (mode) {
2902    case PIPE_TEX_WRAP_REPEAT:
2903       return wrap_linear_repeat;
2904    case PIPE_TEX_WRAP_CLAMP:
2905       return wrap_linear_clamp;
2906    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
2907       return wrap_linear_clamp_to_edge;
2908    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
2909       return wrap_linear_clamp_to_border;
2910    case PIPE_TEX_WRAP_MIRROR_REPEAT:
2911       return wrap_linear_mirror_repeat;
2912    case PIPE_TEX_WRAP_MIRROR_CLAMP:
2913       return wrap_linear_mirror_clamp;
2914    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
2915       return wrap_linear_mirror_clamp_to_edge;
2916    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
2917       return wrap_linear_mirror_clamp_to_border;
2918    default:
2919       assert(0);
2920       return wrap_linear_repeat;
2921    }
2922 }
2923 
2924 
2925 /**
2926  * Is swizzling needed for the given state key?
2927  */
2928 static inline bool
any_swizzle(const struct pipe_sampler_view * view)2929 any_swizzle(const struct pipe_sampler_view *view)
2930 {
2931    return (view->swizzle_r != PIPE_SWIZZLE_X ||
2932            view->swizzle_g != PIPE_SWIZZLE_Y ||
2933            view->swizzle_b != PIPE_SWIZZLE_Z ||
2934            view->swizzle_a != PIPE_SWIZZLE_W);
2935 }
2936 
2937 
2938 static img_filter_func
get_img_filter(const struct sp_sampler_view * sp_sview,const struct pipe_sampler_state * sampler,unsigned filter,bool gather)2939 get_img_filter(const struct sp_sampler_view *sp_sview,
2940                const struct pipe_sampler_state *sampler,
2941                unsigned filter, bool gather)
2942 {
2943    switch (sp_sview->base.target) {
2944    case PIPE_BUFFER:
2945    case PIPE_TEXTURE_1D:
2946       if (filter == PIPE_TEX_FILTER_NEAREST)
2947          return img_filter_1d_nearest;
2948       else
2949          return img_filter_1d_linear;
2950       break;
2951    case PIPE_TEXTURE_1D_ARRAY:
2952       if (filter == PIPE_TEX_FILTER_NEAREST)
2953          return img_filter_1d_array_nearest;
2954       else
2955          return img_filter_1d_array_linear;
2956       break;
2957    case PIPE_TEXTURE_2D:
2958    case PIPE_TEXTURE_RECT:
2959       /* Try for fast path:
2960        */
2961       if (!gather && sp_sview->pot2d &&
2962           sampler->wrap_s == sampler->wrap_t &&
2963           sampler->normalized_coords)
2964       {
2965          switch (sampler->wrap_s) {
2966          case PIPE_TEX_WRAP_REPEAT:
2967             switch (filter) {
2968             case PIPE_TEX_FILTER_NEAREST:
2969                return img_filter_2d_nearest_repeat_POT;
2970             case PIPE_TEX_FILTER_LINEAR:
2971                return img_filter_2d_linear_repeat_POT;
2972             default:
2973                break;
2974             }
2975             break;
2976          case PIPE_TEX_WRAP_CLAMP:
2977             switch (filter) {
2978             case PIPE_TEX_FILTER_NEAREST:
2979                return img_filter_2d_nearest_clamp_POT;
2980             default:
2981                break;
2982             }
2983          }
2984       }
2985       /* Otherwise use default versions:
2986        */
2987       if (filter == PIPE_TEX_FILTER_NEAREST)
2988          return img_filter_2d_nearest;
2989       else
2990          return img_filter_2d_linear;
2991       break;
2992    case PIPE_TEXTURE_2D_ARRAY:
2993       if (filter == PIPE_TEX_FILTER_NEAREST)
2994          return img_filter_2d_array_nearest;
2995       else
2996          return img_filter_2d_array_linear;
2997       break;
2998    case PIPE_TEXTURE_CUBE:
2999       if (filter == PIPE_TEX_FILTER_NEAREST)
3000          return img_filter_cube_nearest;
3001       else
3002          return img_filter_cube_linear;
3003       break;
3004    case PIPE_TEXTURE_CUBE_ARRAY:
3005       if (filter == PIPE_TEX_FILTER_NEAREST)
3006          return img_filter_cube_array_nearest;
3007       else
3008          return img_filter_cube_array_linear;
3009       break;
3010    case PIPE_TEXTURE_3D:
3011       if (filter == PIPE_TEX_FILTER_NEAREST)
3012          return img_filter_3d_nearest;
3013       else
3014          return img_filter_3d_linear;
3015       break;
3016    default:
3017       assert(0);
3018       return img_filter_1d_nearest;
3019    }
3020 }
3021 
3022 /**
3023  * Get mip filter funcs, and optionally both img min filter and img mag
3024  * filter. Note that both img filter function pointers must be either non-NULL
3025  * or NULL.
3026  */
3027 static void
get_filters(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const enum tgsi_sampler_control control,const struct sp_filter_funcs ** funcs,img_filter_func * min,img_filter_func * mag)3028 get_filters(const struct sp_sampler_view *sp_sview,
3029             const struct sp_sampler *sp_samp,
3030             const enum tgsi_sampler_control control,
3031             const struct sp_filter_funcs **funcs,
3032             img_filter_func *min,
3033             img_filter_func *mag)
3034 {
3035    assert(funcs);
3036    if (control == TGSI_SAMPLER_GATHER) {
3037       *funcs = &funcs_nearest;
3038       if (min) {
3039          *min = get_img_filter(sp_sview, &sp_samp->base,
3040                                PIPE_TEX_FILTER_LINEAR, true);
3041       }
3042    } else if (sp_sview->pot2d & sp_samp->min_mag_equal_repeat_linear) {
3043       *funcs = &funcs_linear_2d_linear_repeat_POT;
3044    } else {
3045       *funcs = sp_samp->filter_funcs;
3046       if (min) {
3047          assert(mag);
3048          *min = get_img_filter(sp_sview, &sp_samp->base,
3049                                sp_samp->min_img_filter, false);
3050          if (sp_samp->min_mag_equal) {
3051             *mag = *min;
3052          } else {
3053             *mag = get_img_filter(sp_sview, &sp_samp->base,
3054                                   sp_samp->base.mag_img_filter, false);
3055          }
3056       }
3057    }
3058 }
3059 
3060 static void
sample_mip(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const float s[TGSI_QUAD_SIZE],const float t[TGSI_QUAD_SIZE],const float p[TGSI_QUAD_SIZE],const float c0[TGSI_QUAD_SIZE],const float lod[TGSI_QUAD_SIZE],const struct filter_args * filt_args,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])3061 sample_mip(const struct sp_sampler_view *sp_sview,
3062            const struct sp_sampler *sp_samp,
3063            const float s[TGSI_QUAD_SIZE],
3064            const float t[TGSI_QUAD_SIZE],
3065            const float p[TGSI_QUAD_SIZE],
3066            const float c0[TGSI_QUAD_SIZE],
3067            const float lod[TGSI_QUAD_SIZE],
3068            const struct filter_args *filt_args,
3069            float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
3070 {
3071    const struct sp_filter_funcs *funcs = NULL;
3072    img_filter_func min_img_filter = NULL;
3073    img_filter_func mag_img_filter = NULL;
3074 
3075    get_filters(sp_sview, sp_samp, filt_args->control,
3076                &funcs, &min_img_filter, &mag_img_filter);
3077 
3078    funcs->filter(sp_sview, sp_samp, min_img_filter, mag_img_filter,
3079                  s, t, p, c0, lod, filt_args, rgba);
3080 
3081    if (sp_samp->base.compare_mode != PIPE_TEX_COMPARE_NONE) {
3082       sample_compare(sp_sview, sp_samp, s, t, p, c0,
3083                      lod, filt_args->control, rgba);
3084    }
3085 
3086    if (sp_sview->need_swizzle && filt_args->control != TGSI_SAMPLER_GATHER) {
3087       float rgba_temp[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE];
3088       memcpy(rgba_temp, rgba, sizeof(rgba_temp));
3089       do_swizzling(&sp_sview->base, rgba_temp, rgba);
3090    }
3091 
3092 }
3093 
3094 
3095 /**
3096  * This function uses cube texture coordinates to choose a face of a cube and
3097  * computes the 2D cube face coordinates. Puts face info into the sampler
3098  * faces[] array.
3099  */
3100 static void
convert_cube(const struct sp_sampler_view * sp_sview,const struct sp_sampler * sp_samp,const float s[TGSI_QUAD_SIZE],const float t[TGSI_QUAD_SIZE],const float p[TGSI_QUAD_SIZE],const float c0[TGSI_QUAD_SIZE],float ssss[TGSI_QUAD_SIZE],float tttt[TGSI_QUAD_SIZE],float pppp[TGSI_QUAD_SIZE],uint faces[TGSI_QUAD_SIZE])3101 convert_cube(const struct sp_sampler_view *sp_sview,
3102              const struct sp_sampler *sp_samp,
3103              const float s[TGSI_QUAD_SIZE],
3104              const float t[TGSI_QUAD_SIZE],
3105              const float p[TGSI_QUAD_SIZE],
3106              const float c0[TGSI_QUAD_SIZE],
3107              float ssss[TGSI_QUAD_SIZE],
3108              float tttt[TGSI_QUAD_SIZE],
3109              float pppp[TGSI_QUAD_SIZE],
3110              uint faces[TGSI_QUAD_SIZE])
3111 {
3112    unsigned j;
3113 
3114    pppp[0] = c0[0];
3115    pppp[1] = c0[1];
3116    pppp[2] = c0[2];
3117    pppp[3] = c0[3];
3118    /*
3119      major axis
3120      direction    target                             sc     tc    ma
3121      ----------   -------------------------------    ---    ---   ---
3122      +rx          TEXTURE_CUBE_MAP_POSITIVE_X_EXT    -rz    -ry   rx
3123      -rx          TEXTURE_CUBE_MAP_NEGATIVE_X_EXT    +rz    -ry   rx
3124      +ry          TEXTURE_CUBE_MAP_POSITIVE_Y_EXT    +rx    +rz   ry
3125      -ry          TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT    +rx    -rz   ry
3126      +rz          TEXTURE_CUBE_MAP_POSITIVE_Z_EXT    +rx    -ry   rz
3127      -rz          TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT    -rx    -ry   rz
3128    */
3129 
3130    /* Choose the cube face and compute new s/t coords for the 2D face.
3131     *
3132     * Use the same cube face for all four pixels in the quad.
3133     *
3134     * This isn't ideal, but if we want to use a different cube face
3135     * per pixel in the quad, we'd have to also compute the per-face
3136     * LOD here too.  That's because the four post-face-selection
3137     * texcoords are no longer related to each other (they're
3138     * per-face!)  so we can't use subtraction to compute the partial
3139     * deriviates to compute the LOD.  Doing so (near cube edges
3140     * anyway) gives us pretty much random values.
3141     */
3142    {
3143       /* use the average of the four pixel's texcoords to choose the face */
3144       const float rx = 0.25F * (s[0] + s[1] + s[2] + s[3]);
3145       const float ry = 0.25F * (t[0] + t[1] + t[2] + t[3]);
3146       const float rz = 0.25F * (p[0] + p[1] + p[2] + p[3]);
3147       const float arx = fabsf(rx), ary = fabsf(ry), arz = fabsf(rz);
3148 
3149       if (arx >= ary && arx >= arz) {
3150          const float sign = (rx >= 0.0F) ? 1.0F : -1.0F;
3151          const uint face = (rx >= 0.0F) ?
3152             PIPE_TEX_FACE_POS_X : PIPE_TEX_FACE_NEG_X;
3153          for (j = 0; j < TGSI_QUAD_SIZE; j++) {
3154             const float ima = -0.5F / fabsf(s[j]);
3155             ssss[j] = sign *  p[j] * ima + 0.5F;
3156             tttt[j] =         t[j] * ima + 0.5F;
3157             faces[j] = face;
3158          }
3159       }
3160       else if (ary >= arx && ary >= arz) {
3161          const float sign = (ry >= 0.0F) ? 1.0F : -1.0F;
3162          const uint face = (ry >= 0.0F) ?
3163             PIPE_TEX_FACE_POS_Y : PIPE_TEX_FACE_NEG_Y;
3164          for (j = 0; j < TGSI_QUAD_SIZE; j++) {
3165             const float ima = -0.5F / fabsf(t[j]);
3166             ssss[j] =        -s[j] * ima + 0.5F;
3167             tttt[j] = sign * -p[j] * ima + 0.5F;
3168             faces[j] = face;
3169          }
3170       }
3171       else {
3172          const float sign = (rz >= 0.0F) ? 1.0F : -1.0F;
3173          const uint face = (rz >= 0.0F) ?
3174             PIPE_TEX_FACE_POS_Z : PIPE_TEX_FACE_NEG_Z;
3175          for (j = 0; j < TGSI_QUAD_SIZE; j++) {
3176             const float ima = -0.5F / fabsf(p[j]);
3177             ssss[j] = sign * -s[j] * ima + 0.5F;
3178             tttt[j] =         t[j] * ima + 0.5F;
3179             faces[j] = face;
3180          }
3181       }
3182    }
3183 }
3184 
3185 
3186 static void
sp_get_dims(const struct sp_sampler_view * sp_sview,int level,int dims[4])3187 sp_get_dims(const struct sp_sampler_view *sp_sview,
3188             int level,
3189             int dims[4])
3190 {
3191    const struct pipe_sampler_view *view = &sp_sview->base;
3192    const struct pipe_resource *texture = view->texture;
3193 
3194    if (view->target == PIPE_BUFFER) {
3195       dims[0] = view->u.buf.size / util_format_get_blocksize(view->format);
3196       /* the other values are undefined, but let's avoid potential valgrind
3197        * warnings.
3198        */
3199       dims[1] = dims[2] = dims[3] = 0;
3200       return;
3201    }
3202 
3203    /* undefined according to EXT_gpu_program */
3204    level += view->u.tex.first_level;
3205    if (level > view->u.tex.last_level)
3206       return;
3207 
3208    dims[3] = view->u.tex.last_level - view->u.tex.first_level + 1;
3209    dims[0] = u_minify(texture->width0, level);
3210 
3211    switch (view->target) {
3212    case PIPE_TEXTURE_1D_ARRAY:
3213       dims[1] = view->u.tex.last_layer - view->u.tex.first_layer + 1;
3214       /* fallthrough */
3215    case PIPE_TEXTURE_1D:
3216       return;
3217    case PIPE_TEXTURE_2D_ARRAY:
3218       dims[2] = view->u.tex.last_layer - view->u.tex.first_layer + 1;
3219       /* fallthrough */
3220    case PIPE_TEXTURE_2D:
3221    case PIPE_TEXTURE_CUBE:
3222    case PIPE_TEXTURE_RECT:
3223       dims[1] = u_minify(texture->height0, level);
3224       return;
3225    case PIPE_TEXTURE_3D:
3226       dims[1] = u_minify(texture->height0, level);
3227       dims[2] = u_minify(texture->depth0, level);
3228       return;
3229    case PIPE_TEXTURE_CUBE_ARRAY:
3230       dims[1] = u_minify(texture->height0, level);
3231       dims[2] = (view->u.tex.last_layer - view->u.tex.first_layer + 1) / 6;
3232       break;
3233    default:
3234       assert(!"unexpected texture target in sp_get_dims()");
3235       return;
3236    }
3237 }
3238 
3239 /**
3240  * This function is only used for getting unfiltered texels via the
3241  * TXF opcode.  The GL spec says that out-of-bounds texel fetches
3242  * produce undefined results.  Instead of crashing, lets just clamp
3243  * coords to the texture image size.
3244  */
3245 static void
sp_get_texels(const struct sp_sampler_view * sp_sview,const int v_i[TGSI_QUAD_SIZE],const int v_j[TGSI_QUAD_SIZE],const int v_k[TGSI_QUAD_SIZE],const int lod[TGSI_QUAD_SIZE],const int8_t offset[3],float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])3246 sp_get_texels(const struct sp_sampler_view *sp_sview,
3247               const int v_i[TGSI_QUAD_SIZE],
3248               const int v_j[TGSI_QUAD_SIZE],
3249               const int v_k[TGSI_QUAD_SIZE],
3250               const int lod[TGSI_QUAD_SIZE],
3251               const int8_t offset[3],
3252               float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
3253 {
3254    union tex_tile_address addr;
3255    const struct pipe_resource *texture = sp_sview->base.texture;
3256    int j, c;
3257    const float *tx;
3258    /* TODO write a better test for LOD */
3259    const unsigned level =
3260       sp_sview->base.target == PIPE_BUFFER ? 0 :
3261       CLAMP(lod[0] + sp_sview->base.u.tex.first_level,
3262             sp_sview->base.u.tex.first_level,
3263             sp_sview->base.u.tex.last_level);
3264    const int width = u_minify(texture->width0, level);
3265    const int height = u_minify(texture->height0, level);
3266    const int depth = u_minify(texture->depth0, level);
3267    unsigned elem_size, first_element, last_element;
3268 
3269    addr.value = 0;
3270    addr.bits.level = level;
3271 
3272    switch (sp_sview->base.target) {
3273    case PIPE_BUFFER:
3274       elem_size = util_format_get_blocksize(sp_sview->base.format);
3275       first_element = sp_sview->base.u.buf.offset / elem_size;
3276       last_element = (sp_sview->base.u.buf.offset +
3277                       sp_sview->base.u.buf.size) / elem_size - 1;
3278       for (j = 0; j < TGSI_QUAD_SIZE; j++) {
3279          const int x = CLAMP(v_i[j] + offset[0] +
3280                              first_element,
3281                              first_element,
3282                              last_element);
3283          tx = get_texel_2d_no_border(sp_sview, addr, x, 0);
3284          for (c = 0; c < 4; c++) {
3285             rgba[c][j] = tx[c];
3286          }
3287       }
3288       break;
3289    case PIPE_TEXTURE_1D:
3290       for (j = 0; j < TGSI_QUAD_SIZE; j++) {
3291          const int x = CLAMP(v_i[j] + offset[0], 0, width - 1);
3292          tx = get_texel_2d_no_border(sp_sview, addr, x,
3293                                      sp_sview->base.u.tex.first_layer);
3294          for (c = 0; c < 4; c++) {
3295             rgba[c][j] = tx[c];
3296          }
3297       }
3298       break;
3299    case PIPE_TEXTURE_1D_ARRAY:
3300       for (j = 0; j < TGSI_QUAD_SIZE; j++) {
3301          const int x = CLAMP(v_i[j] + offset[0], 0, width - 1);
3302          const int y = CLAMP(v_j[j], sp_sview->base.u.tex.first_layer,
3303                              sp_sview->base.u.tex.last_layer);
3304          tx = get_texel_2d_no_border(sp_sview, addr, x, y);
3305          for (c = 0; c < 4; c++) {
3306             rgba[c][j] = tx[c];
3307          }
3308       }
3309       break;
3310    case PIPE_TEXTURE_2D:
3311    case PIPE_TEXTURE_RECT:
3312       for (j = 0; j < TGSI_QUAD_SIZE; j++) {
3313          const int x = CLAMP(v_i[j] + offset[0], 0, width - 1);
3314          const int y = CLAMP(v_j[j] + offset[1], 0, height - 1);
3315          tx = get_texel_3d_no_border(sp_sview, addr, x, y,
3316                                      sp_sview->base.u.tex.first_layer);
3317          for (c = 0; c < 4; c++) {
3318             rgba[c][j] = tx[c];
3319          }
3320       }
3321       break;
3322    case PIPE_TEXTURE_2D_ARRAY:
3323       for (j = 0; j < TGSI_QUAD_SIZE; j++) {
3324          const int x = CLAMP(v_i[j] + offset[0], 0, width - 1);
3325          const int y = CLAMP(v_j[j] + offset[1], 0, height - 1);
3326          const int layer = CLAMP(v_k[j], sp_sview->base.u.tex.first_layer,
3327                                  sp_sview->base.u.tex.last_layer);
3328          tx = get_texel_3d_no_border(sp_sview, addr, x, y, layer);
3329          for (c = 0; c < 4; c++) {
3330             rgba[c][j] = tx[c];
3331          }
3332       }
3333       break;
3334    case PIPE_TEXTURE_3D:
3335       for (j = 0; j < TGSI_QUAD_SIZE; j++) {
3336          int x = CLAMP(v_i[j] + offset[0], 0, width - 1);
3337          int y = CLAMP(v_j[j] + offset[1], 0, height - 1);
3338          int z = CLAMP(v_k[j] + offset[2], 0, depth - 1);
3339          tx = get_texel_3d_no_border(sp_sview, addr, x, y, z);
3340          for (c = 0; c < 4; c++) {
3341             rgba[c][j] = tx[c];
3342          }
3343       }
3344       break;
3345    case PIPE_TEXTURE_CUBE: /* TXF can't work on CUBE according to spec */
3346    case PIPE_TEXTURE_CUBE_ARRAY:
3347    default:
3348       assert(!"Unknown or CUBE texture type in TXF processing\n");
3349       break;
3350    }
3351 
3352    if (sp_sview->need_swizzle) {
3353       float rgba_temp[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE];
3354       memcpy(rgba_temp, rgba, sizeof(rgba_temp));
3355       do_swizzling(&sp_sview->base, rgba_temp, rgba);
3356    }
3357 }
3358 
3359 
3360 void *
softpipe_create_sampler_state(struct pipe_context * pipe,const struct pipe_sampler_state * sampler)3361 softpipe_create_sampler_state(struct pipe_context *pipe,
3362                               const struct pipe_sampler_state *sampler)
3363 {
3364    struct sp_sampler *samp = CALLOC_STRUCT(sp_sampler);
3365 
3366    samp->base = *sampler;
3367 
3368    /* Note that (for instance) linear_texcoord_s and
3369     * nearest_texcoord_s may be active at the same time, if the
3370     * sampler min_img_filter differs from its mag_img_filter.
3371     */
3372    if (sampler->normalized_coords) {
3373       samp->linear_texcoord_s = get_linear_wrap( sampler->wrap_s );
3374       samp->linear_texcoord_t = get_linear_wrap( sampler->wrap_t );
3375       samp->linear_texcoord_p = get_linear_wrap( sampler->wrap_r );
3376 
3377       samp->nearest_texcoord_s = get_nearest_wrap( sampler->wrap_s );
3378       samp->nearest_texcoord_t = get_nearest_wrap( sampler->wrap_t );
3379       samp->nearest_texcoord_p = get_nearest_wrap( sampler->wrap_r );
3380    }
3381    else {
3382       samp->linear_texcoord_s = get_linear_unorm_wrap( sampler->wrap_s );
3383       samp->linear_texcoord_t = get_linear_unorm_wrap( sampler->wrap_t );
3384       samp->linear_texcoord_p = get_linear_unorm_wrap( sampler->wrap_r );
3385 
3386       samp->nearest_texcoord_s = get_nearest_unorm_wrap( sampler->wrap_s );
3387       samp->nearest_texcoord_t = get_nearest_unorm_wrap( sampler->wrap_t );
3388       samp->nearest_texcoord_p = get_nearest_unorm_wrap( sampler->wrap_r );
3389    }
3390 
3391    samp->min_img_filter = sampler->min_img_filter;
3392 
3393    switch (sampler->min_mip_filter) {
3394    case PIPE_TEX_MIPFILTER_NONE:
3395       if (sampler->min_img_filter == sampler->mag_img_filter)
3396          samp->filter_funcs = &funcs_none_no_filter_select;
3397       else
3398          samp->filter_funcs = &funcs_none;
3399       break;
3400 
3401    case PIPE_TEX_MIPFILTER_NEAREST:
3402       samp->filter_funcs = &funcs_nearest;
3403       break;
3404 
3405    case PIPE_TEX_MIPFILTER_LINEAR:
3406       if (sampler->min_img_filter == sampler->mag_img_filter &&
3407           sampler->normalized_coords &&
3408           sampler->wrap_s == PIPE_TEX_WRAP_REPEAT &&
3409           sampler->wrap_t == PIPE_TEX_WRAP_REPEAT &&
3410           sampler->min_img_filter == PIPE_TEX_FILTER_LINEAR &&
3411           sampler->max_anisotropy <= 1) {
3412          samp->min_mag_equal_repeat_linear = TRUE;
3413       }
3414       samp->filter_funcs = &funcs_linear;
3415 
3416       /* Anisotropic filtering extension. */
3417       if (sampler->max_anisotropy > 1) {
3418          samp->filter_funcs = &funcs_linear_aniso;
3419 
3420          /* Override min_img_filter:
3421           * min_img_filter needs to be set to NEAREST since we need to access
3422           * each texture pixel as it is and weight it later; using linear
3423           * filters will have incorrect results.
3424           * By setting the filter to NEAREST here, we can avoid calling the
3425           * generic img_filter_2d_nearest in the anisotropic filter function,
3426           * making it possible to use one of the accelerated implementations
3427           */
3428          samp->min_img_filter = PIPE_TEX_FILTER_NEAREST;
3429 
3430          /* on first access create the lookup table containing the filter weights. */
3431         if (!weightLut) {
3432            create_filter_table();
3433         }
3434       }
3435       break;
3436    }
3437    if (samp->min_img_filter == sampler->mag_img_filter) {
3438       samp->min_mag_equal = TRUE;
3439    }
3440 
3441    return (void *)samp;
3442 }
3443 
3444 
3445 compute_lambda_func
softpipe_get_lambda_func(const struct pipe_sampler_view * view,unsigned shader)3446 softpipe_get_lambda_func(const struct pipe_sampler_view *view, unsigned shader)
3447 {
3448    if (shader != PIPE_SHADER_FRAGMENT)
3449       return compute_lambda_vert;
3450 
3451    switch (view->target) {
3452    case PIPE_BUFFER:
3453    case PIPE_TEXTURE_1D:
3454    case PIPE_TEXTURE_1D_ARRAY:
3455       return compute_lambda_1d;
3456    case PIPE_TEXTURE_2D:
3457    case PIPE_TEXTURE_2D_ARRAY:
3458    case PIPE_TEXTURE_RECT:
3459    case PIPE_TEXTURE_CUBE:
3460    case PIPE_TEXTURE_CUBE_ARRAY:
3461       return compute_lambda_2d;
3462    case PIPE_TEXTURE_3D:
3463       return compute_lambda_3d;
3464    default:
3465       assert(0);
3466       return compute_lambda_1d;
3467    }
3468 }
3469 
3470 
3471 struct pipe_sampler_view *
softpipe_create_sampler_view(struct pipe_context * pipe,struct pipe_resource * resource,const struct pipe_sampler_view * templ)3472 softpipe_create_sampler_view(struct pipe_context *pipe,
3473                              struct pipe_resource *resource,
3474                              const struct pipe_sampler_view *templ)
3475 {
3476    struct sp_sampler_view *sview = CALLOC_STRUCT(sp_sampler_view);
3477    const struct softpipe_resource *spr = (struct softpipe_resource *)resource;
3478 
3479    if (sview) {
3480       struct pipe_sampler_view *view = &sview->base;
3481       *view = *templ;
3482       view->reference.count = 1;
3483       view->texture = NULL;
3484       pipe_resource_reference(&view->texture, resource);
3485       view->context = pipe;
3486 
3487 #ifdef DEBUG
3488      /*
3489       * This is possibly too lenient, but the primary reason is just
3490       * to catch state trackers which forget to initialize this, so
3491       * it only catches clearly impossible view targets.
3492       */
3493       if (view->target != resource->target) {
3494          if (view->target == PIPE_TEXTURE_1D)
3495             assert(resource->target == PIPE_TEXTURE_1D_ARRAY);
3496          else if (view->target == PIPE_TEXTURE_1D_ARRAY)
3497             assert(resource->target == PIPE_TEXTURE_1D);
3498          else if (view->target == PIPE_TEXTURE_2D)
3499             assert(resource->target == PIPE_TEXTURE_2D_ARRAY ||
3500                    resource->target == PIPE_TEXTURE_CUBE ||
3501                    resource->target == PIPE_TEXTURE_CUBE_ARRAY);
3502          else if (view->target == PIPE_TEXTURE_2D_ARRAY)
3503             assert(resource->target == PIPE_TEXTURE_2D ||
3504                    resource->target == PIPE_TEXTURE_CUBE ||
3505                    resource->target == PIPE_TEXTURE_CUBE_ARRAY);
3506          else if (view->target == PIPE_TEXTURE_CUBE)
3507             assert(resource->target == PIPE_TEXTURE_CUBE_ARRAY ||
3508                    resource->target == PIPE_TEXTURE_2D_ARRAY);
3509          else if (view->target == PIPE_TEXTURE_CUBE_ARRAY)
3510             assert(resource->target == PIPE_TEXTURE_CUBE ||
3511                    resource->target == PIPE_TEXTURE_2D_ARRAY);
3512          else
3513             assert(0);
3514       }
3515 #endif
3516 
3517       if (any_swizzle(view)) {
3518          sview->need_swizzle = TRUE;
3519       }
3520 
3521       sview->need_cube_convert = (view->target == PIPE_TEXTURE_CUBE ||
3522                                   view->target == PIPE_TEXTURE_CUBE_ARRAY);
3523       sview->pot2d = spr->pot &&
3524                      (view->target == PIPE_TEXTURE_2D ||
3525                       view->target == PIPE_TEXTURE_RECT);
3526 
3527       sview->xpot = util_logbase2( resource->width0 );
3528       sview->ypot = util_logbase2( resource->height0 );
3529    }
3530 
3531    return (struct pipe_sampler_view *) sview;
3532 }
3533 
3534 
3535 static inline const struct sp_tgsi_sampler *
sp_tgsi_sampler_cast_c(const struct tgsi_sampler * sampler)3536 sp_tgsi_sampler_cast_c(const struct tgsi_sampler *sampler)
3537 {
3538    return (const struct sp_tgsi_sampler *)sampler;
3539 }
3540 
3541 
3542 static void
sp_tgsi_get_dims(struct tgsi_sampler * tgsi_sampler,const unsigned sview_index,int level,int dims[4])3543 sp_tgsi_get_dims(struct tgsi_sampler *tgsi_sampler,
3544                  const unsigned sview_index,
3545                  int level, int dims[4])
3546 {
3547    const struct sp_tgsi_sampler *sp_samp =
3548       sp_tgsi_sampler_cast_c(tgsi_sampler);
3549 
3550    assert(sview_index < PIPE_MAX_SHADER_SAMPLER_VIEWS);
3551    /* always have a view here but texture is NULL if no sampler view was set. */
3552    if (!sp_samp->sp_sview[sview_index].base.texture) {
3553       dims[0] = dims[1] = dims[2] = dims[3] = 0;
3554       return;
3555    }
3556    sp_get_dims(&sp_samp->sp_sview[sview_index], level, dims);
3557 }
3558 
3559 
3560 static void
sp_tgsi_get_samples(struct tgsi_sampler * tgsi_sampler,const unsigned sview_index,const unsigned sampler_index,const float s[TGSI_QUAD_SIZE],const float t[TGSI_QUAD_SIZE],const float p[TGSI_QUAD_SIZE],const float c0[TGSI_QUAD_SIZE],const float lod[TGSI_QUAD_SIZE],float derivs[3][2][TGSI_QUAD_SIZE],const int8_t offset[3],enum tgsi_sampler_control control,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])3561 sp_tgsi_get_samples(struct tgsi_sampler *tgsi_sampler,
3562                     const unsigned sview_index,
3563                     const unsigned sampler_index,
3564                     const float s[TGSI_QUAD_SIZE],
3565                     const float t[TGSI_QUAD_SIZE],
3566                     const float p[TGSI_QUAD_SIZE],
3567                     const float c0[TGSI_QUAD_SIZE],
3568                     const float lod[TGSI_QUAD_SIZE],
3569                     float derivs[3][2][TGSI_QUAD_SIZE],
3570                     const int8_t offset[3],
3571                     enum tgsi_sampler_control control,
3572                     float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
3573 {
3574    const struct sp_tgsi_sampler *sp_tgsi_samp =
3575       sp_tgsi_sampler_cast_c(tgsi_sampler);
3576    const struct sp_sampler_view *sp_sview;
3577    const struct sp_sampler *sp_samp;
3578    struct filter_args filt_args;
3579 
3580    assert(sview_index < PIPE_MAX_SHADER_SAMPLER_VIEWS);
3581    assert(sampler_index < PIPE_MAX_SAMPLERS);
3582    assert(sp_tgsi_samp->sp_sampler[sampler_index]);
3583 
3584    sp_sview = &sp_tgsi_samp->sp_sview[sview_index];
3585    sp_samp = sp_tgsi_samp->sp_sampler[sampler_index];
3586    /* always have a view here but texture is NULL if no sampler view was set. */
3587    if (!sp_sview->base.texture) {
3588       int i, j;
3589       for (j = 0; j < TGSI_NUM_CHANNELS; j++) {
3590          for (i = 0; i < TGSI_QUAD_SIZE; i++) {
3591             rgba[j][i] = 0.0f;
3592          }
3593       }
3594       return;
3595    }
3596 
3597    filt_args.control = control;
3598    filt_args.offset = offset;
3599 
3600    if (sp_sview->need_cube_convert) {
3601       float cs[TGSI_QUAD_SIZE];
3602       float ct[TGSI_QUAD_SIZE];
3603       float cp[TGSI_QUAD_SIZE];
3604       uint faces[TGSI_QUAD_SIZE];
3605 
3606       convert_cube(sp_sview, sp_samp, s, t, p, c0, cs, ct, cp, faces);
3607 
3608       filt_args.faces = faces;
3609       sample_mip(sp_sview, sp_samp, cs, ct, cp, c0, lod, &filt_args, rgba);
3610    } else {
3611       static const uint zero_faces[TGSI_QUAD_SIZE] = {0, 0, 0, 0};
3612 
3613       filt_args.faces = zero_faces;
3614       sample_mip(sp_sview, sp_samp, s, t, p, c0, lod, &filt_args, rgba);
3615    }
3616 }
3617 
3618 static void
sp_tgsi_query_lod(const struct tgsi_sampler * tgsi_sampler,const unsigned sview_index,const unsigned sampler_index,const float s[TGSI_QUAD_SIZE],const float t[TGSI_QUAD_SIZE],const float p[TGSI_QUAD_SIZE],const float c0[TGSI_QUAD_SIZE],const enum tgsi_sampler_control control,float mipmap[TGSI_QUAD_SIZE],float lod[TGSI_QUAD_SIZE])3619 sp_tgsi_query_lod(const struct tgsi_sampler *tgsi_sampler,
3620                   const unsigned sview_index,
3621                   const unsigned sampler_index,
3622                   const float s[TGSI_QUAD_SIZE],
3623                   const float t[TGSI_QUAD_SIZE],
3624                   const float p[TGSI_QUAD_SIZE],
3625                   const float c0[TGSI_QUAD_SIZE],
3626                   const enum tgsi_sampler_control control,
3627                   float mipmap[TGSI_QUAD_SIZE],
3628                   float lod[TGSI_QUAD_SIZE])
3629 {
3630    static const float lod_in[TGSI_QUAD_SIZE] = { 0.0, 0.0, 0.0, 0.0 };
3631 
3632    const struct sp_tgsi_sampler *sp_tgsi_samp =
3633       sp_tgsi_sampler_cast_c(tgsi_sampler);
3634    const struct sp_sampler_view *sp_sview;
3635    const struct sp_sampler *sp_samp;
3636    const struct sp_filter_funcs *funcs;
3637    int i;
3638 
3639    assert(sview_index < PIPE_MAX_SHADER_SAMPLER_VIEWS);
3640    assert(sampler_index < PIPE_MAX_SAMPLERS);
3641    assert(sp_tgsi_samp->sp_sampler[sampler_index]);
3642 
3643    sp_sview = &sp_tgsi_samp->sp_sview[sview_index];
3644    sp_samp = sp_tgsi_samp->sp_sampler[sampler_index];
3645    /* always have a view here but texture is NULL if no sampler view was
3646     * set. */
3647    if (!sp_sview->base.texture) {
3648       for (i = 0; i < TGSI_QUAD_SIZE; i++) {
3649          mipmap[i] = 0.0f;
3650          lod[i] = 0.0f;
3651       }
3652       return;
3653    }
3654 
3655    if (sp_sview->need_cube_convert) {
3656       float cs[TGSI_QUAD_SIZE];
3657       float ct[TGSI_QUAD_SIZE];
3658       float cp[TGSI_QUAD_SIZE];
3659       uint unused_faces[TGSI_QUAD_SIZE];
3660 
3661       convert_cube(sp_sview, sp_samp, s, t, p, c0, cs, ct, cp, unused_faces);
3662       compute_lambda_lod_unclamped(sp_sview, sp_samp,
3663                                    cs, ct, cp, lod_in, control, lod);
3664    } else {
3665       compute_lambda_lod_unclamped(sp_sview, sp_samp,
3666                                    s, t, p, lod_in, control, lod);
3667    }
3668 
3669    get_filters(sp_sview, sp_samp, control, &funcs, NULL, NULL);
3670    funcs->relative_level(sp_sview, sp_samp, lod, mipmap);
3671 }
3672 
3673 static void
sp_tgsi_get_texel(struct tgsi_sampler * tgsi_sampler,const unsigned sview_index,const int i[TGSI_QUAD_SIZE],const int j[TGSI_QUAD_SIZE],const int k[TGSI_QUAD_SIZE],const int lod[TGSI_QUAD_SIZE],const int8_t offset[3],float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])3674 sp_tgsi_get_texel(struct tgsi_sampler *tgsi_sampler,
3675                   const unsigned sview_index,
3676                   const int i[TGSI_QUAD_SIZE],
3677                   const int j[TGSI_QUAD_SIZE], const int k[TGSI_QUAD_SIZE],
3678                   const int lod[TGSI_QUAD_SIZE], const int8_t offset[3],
3679                   float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
3680 {
3681    const struct sp_tgsi_sampler *sp_samp =
3682       sp_tgsi_sampler_cast_c(tgsi_sampler);
3683 
3684    assert(sview_index < PIPE_MAX_SHADER_SAMPLER_VIEWS);
3685    /* always have a view here but texture is NULL if no sampler view was set. */
3686    if (!sp_samp->sp_sview[sview_index].base.texture) {
3687       int i, j;
3688       for (j = 0; j < TGSI_NUM_CHANNELS; j++) {
3689          for (i = 0; i < TGSI_QUAD_SIZE; i++) {
3690             rgba[j][i] = 0.0f;
3691          }
3692       }
3693       return;
3694    }
3695    sp_get_texels(&sp_samp->sp_sview[sview_index], i, j, k, lod, offset, rgba);
3696 }
3697 
3698 
3699 struct sp_tgsi_sampler *
sp_create_tgsi_sampler(void)3700 sp_create_tgsi_sampler(void)
3701 {
3702    struct sp_tgsi_sampler *samp = CALLOC_STRUCT(sp_tgsi_sampler);
3703    if (!samp)
3704       return NULL;
3705 
3706    samp->base.get_dims = sp_tgsi_get_dims;
3707    samp->base.get_samples = sp_tgsi_get_samples;
3708    samp->base.get_texel = sp_tgsi_get_texel;
3709    samp->base.query_lod = sp_tgsi_query_lod;
3710 
3711    return samp;
3712 }
3713