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