1 /**************************************************************************
3 * Copyright 2007 VMware, Inc.
5 * Copyright 2008-2010 VMware, Inc. All rights reserved.
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:
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
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.
27 **************************************************************************/
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"
50 /** Set to one to help debug texture sampling */
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.
70 * Linear interpolation macro
73 lerp(float a
, float v0
, float v1
)
75 return v0
+ a
* (v1
- v0
);
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
88 lerp_2d(float a
, float b
,
89 float v00
, float v10
, float v01
, float v11
)
91 const float temp0
= lerp(a
, v00
, v10
);
92 const float temp1
= lerp(a
, v01
, v11
);
93 return lerp(b
, temp0
, temp1
);
98 * As above, but 3D interpolation of 8 values.
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
)
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
);
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).
119 repeat(int coord
, unsigned size
)
121 return (coord
+ size
* 1024) % size
;
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
134 wrap_nearest_repeat(float s
, unsigned size
, int offset
, int *icoord
)
136 /* s limited to [0,1) */
137 /* i limited to [0,size-1] */
138 const int i
= util_ifloor(s
* size
);
139 *icoord
= repeat(i
+ offset
, size
);
144 wrap_nearest_clamp(float s
, unsigned size
, int offset
, int *icoord
)
146 /* s limited to [0,1] */
147 /* i limited to [0,size-1] */
155 *icoord
= util_ifloor(s
);
160 wrap_nearest_clamp_to_edge(float s
, unsigned size
, int offset
, int *icoord
)
162 /* s limited to [min,max] */
163 /* i limited to [0, size-1] */
164 const float min
= 0.5F
;
165 const float max
= (float)size
- 0.5F
;
175 *icoord
= util_ifloor(s
);
180 wrap_nearest_clamp_to_border(float s
, unsigned size
, int offset
, int *icoord
)
182 /* s limited to [min,max] */
183 /* i limited to [-1, size] */
184 const float min
= -0.5F
;
185 const float max
= size
+ 0.5F
;
194 *icoord
= util_ifloor(s
);
198 wrap_nearest_mirror_repeat(float s
, unsigned size
, int offset
, int *icoord
)
200 const float min
= 1.0F
/ (2.0F
* size
);
201 const float max
= 1.0F
- min
;
205 s
+= (float)offset
/ size
;
206 flr
= util_ifloor(s
);
215 *icoord
= util_ifloor(u
* size
);
220 wrap_nearest_mirror_clamp(float s
, unsigned size
, int offset
, int *icoord
)
222 /* s limited to [0,1] */
223 /* i limited to [0,size-1] */
224 const float u
= fabsf(s
* size
+ offset
);
230 *icoord
= util_ifloor(u
);
235 wrap_nearest_mirror_clamp_to_edge(float s
, unsigned size
, int offset
, int *icoord
)
237 /* s limited to [min,max] */
238 /* i limited to [0, size-1] */
239 const float min
= 0.5F
;
240 const float max
= (float)size
- 0.5F
;
241 const float u
= fabsf(s
* size
+ offset
);
248 *icoord
= util_ifloor(u
);
253 wrap_nearest_mirror_clamp_to_border(float s
, unsigned size
, int offset
, int *icoord
)
255 /* u limited to [-0.5, size-0.5] */
256 const float min
= -0.5F
;
257 const float max
= (float)size
+ 0.5F
;
258 const float u
= fabsf(s
* size
+ offset
);
265 *icoord
= util_ifloor(u
);
270 * Used to compute texel locations for linear sampling
271 * \param wrapMode PIPE_TEX_WRAP_x
272 * \param s the texcoord
273 * \param size the texture image size
274 * \param icoord0 returns first texture index
275 * \param icoord1 returns second texture index (usually icoord0 + 1)
276 * \param w returns blend factor/weight between texture indices
277 * \param icoord returns the computed integer texture coord
280 wrap_linear_repeat(float s
, unsigned size
, int offset
,
281 int *icoord0
, int *icoord1
, float *w
)
283 const float u
= s
* size
- 0.5F
;
284 *icoord0
= repeat(util_ifloor(u
) + offset
, size
);
285 *icoord1
= repeat(*icoord0
+ 1, size
);
291 wrap_linear_clamp(float s
, unsigned size
, int offset
,
292 int *icoord0
, int *icoord1
, float *w
)
294 const float u
= CLAMP(s
* size
+ offset
, 0.0F
, (float)size
) - 0.5f
;
296 *icoord0
= util_ifloor(u
);
297 *icoord1
= *icoord0
+ 1;
303 wrap_linear_clamp_to_edge(float s
, unsigned size
, int offset
,
304 int *icoord0
, int *icoord1
, float *w
)
306 const float u
= CLAMP(s
* size
+ offset
, 0.0F
, (float)size
) - 0.5f
;
307 *icoord0
= util_ifloor(u
);
308 *icoord1
= *icoord0
+ 1;
311 if (*icoord1
>= (int) size
)
318 wrap_linear_clamp_to_border(float s
, unsigned size
, int offset
,
319 int *icoord0
, int *icoord1
, float *w
)
321 const float min
= -0.5F
;
322 const float max
= (float)size
+ 0.5F
;
323 const float u
= CLAMP(s
* size
+ offset
, min
, max
) - 0.5f
;
324 *icoord0
= util_ifloor(u
);
325 *icoord1
= *icoord0
+ 1;
331 wrap_linear_mirror_repeat(float s
, unsigned size
, int offset
,
332 int *icoord0
, int *icoord1
, float *w
)
337 s
+= (float)offset
/ size
;
338 flr
= util_ifloor(s
);
343 *icoord0
= util_ifloor(u
);
344 *icoord1
= *icoord0
+ 1;
347 if (*icoord1
>= (int) size
)
354 wrap_linear_mirror_clamp(float s
, unsigned size
, int offset
,
355 int *icoord0
, int *icoord1
, float *w
)
357 float u
= fabsf(s
* size
+ offset
);
361 *icoord0
= util_ifloor(u
);
362 *icoord1
= *icoord0
+ 1;
368 wrap_linear_mirror_clamp_to_edge(float s
, unsigned size
, int offset
,
369 int *icoord0
, int *icoord1
, float *w
)
371 float u
= fabsf(s
* size
+ offset
);
375 *icoord0
= util_ifloor(u
);
376 *icoord1
= *icoord0
+ 1;
379 if (*icoord1
>= (int) size
)
386 wrap_linear_mirror_clamp_to_border(float s
, unsigned size
, int offset
,
387 int *icoord0
, int *icoord1
, float *w
)
389 const float min
= -0.5F
;
390 const float max
= size
+ 0.5F
;
391 const float t
= fabsf(s
* size
+ offset
);
392 const float u
= CLAMP(t
, min
, max
) - 0.5F
;
393 *icoord0
= util_ifloor(u
);
394 *icoord1
= *icoord0
+ 1;
400 * PIPE_TEX_WRAP_CLAMP for nearest sampling, unnormalized coords.
403 wrap_nearest_unorm_clamp(float s
, unsigned size
, int offset
, int *icoord
)
405 const int i
= util_ifloor(s
);
406 *icoord
= CLAMP(i
+ offset
, 0, (int) size
-1);
411 * PIPE_TEX_WRAP_CLAMP_TO_BORDER for nearest sampling, unnormalized coords.
414 wrap_nearest_unorm_clamp_to_border(float s
, unsigned size
, int offset
, int *icoord
)
416 *icoord
= util_ifloor( CLAMP(s
+ offset
, -0.5F
, (float) size
+ 0.5F
) );
421 * PIPE_TEX_WRAP_CLAMP_TO_EDGE for nearest sampling, unnormalized coords.
424 wrap_nearest_unorm_clamp_to_edge(float s
, unsigned size
, int offset
, int *icoord
)
426 *icoord
= util_ifloor( CLAMP(s
+ offset
, 0.5F
, (float) size
- 0.5F
) );
431 * PIPE_TEX_WRAP_CLAMP for linear sampling, unnormalized coords.
434 wrap_linear_unorm_clamp(float s
, unsigned size
, int offset
,
435 int *icoord0
, int *icoord1
, float *w
)
437 /* Not exactly what the spec says, but it matches NVIDIA output */
438 const float u
= CLAMP(s
+ offset
- 0.5F
, 0.0f
, (float) size
- 1.0f
);
439 *icoord0
= util_ifloor(u
);
440 *icoord1
= *icoord0
+ 1;
446 * PIPE_TEX_WRAP_CLAMP_TO_BORDER for linear sampling, unnormalized coords.
449 wrap_linear_unorm_clamp_to_border(float s
, unsigned size
, int offset
,
450 int *icoord0
, int *icoord1
, float *w
)
452 const float u
= CLAMP(s
+ offset
, -0.5F
, (float) size
+ 0.5F
) - 0.5F
;
453 *icoord0
= util_ifloor(u
);
454 *icoord1
= *icoord0
+ 1;
455 if (*icoord1
> (int) size
- 1)
462 * PIPE_TEX_WRAP_CLAMP_TO_EDGE for linear sampling, unnormalized coords.
465 wrap_linear_unorm_clamp_to_edge(float s
, unsigned size
, int offset
,
466 int *icoord0
, int *icoord1
, float *w
)
468 const float u
= CLAMP(s
+ offset
, +0.5F
, (float) size
- 0.5F
) - 0.5F
;
469 *icoord0
= util_ifloor(u
);
470 *icoord1
= *icoord0
+ 1;
471 if (*icoord1
> (int) size
- 1)
478 * Do coordinate to array index conversion. For array textures.
481 coord_to_layer(float coord
, unsigned first_layer
, unsigned last_layer
)
483 const int c
= util_ifloor(coord
+ 0.5F
);
484 return CLAMP(c
, (int)first_layer
, (int)last_layer
);
488 compute_gradient_1d(const float s
[TGSI_QUAD_SIZE
],
489 const float t
[TGSI_QUAD_SIZE
],
490 const float p
[TGSI_QUAD_SIZE
],
491 float derivs
[3][2][TGSI_QUAD_SIZE
])
493 memset(derivs
, 0, 6 * TGSI_QUAD_SIZE
* sizeof(float));
494 derivs
[0][0][0] = s
[QUAD_BOTTOM_RIGHT
] - s
[QUAD_BOTTOM_LEFT
];
495 derivs
[0][1][0] = s
[QUAD_TOP_LEFT
] - s
[QUAD_BOTTOM_LEFT
];
499 compute_lambda_1d_explicit_gradients(const struct sp_sampler_view
*sview
,
500 const float derivs
[3][2][TGSI_QUAD_SIZE
],
503 const struct pipe_resource
*texture
= sview
->base
.texture
;
504 const float dsdx
= fabsf(derivs
[0][0][quad
]);
505 const float dsdy
= fabsf(derivs
[0][1][quad
]);
506 const float rho
= MAX2(dsdx
, dsdy
) * u_minify(texture
->width0
, sview
->base
.u
.tex
.first_level
);
507 return util_fast_log2(rho
);
512 * Examine the quad's texture coordinates to compute the partial
513 * derivatives w.r.t X and Y, then compute lambda (level of detail).
516 compute_lambda_1d(const struct sp_sampler_view
*sview
,
517 const float s
[TGSI_QUAD_SIZE
],
518 const float t
[TGSI_QUAD_SIZE
],
519 const float p
[TGSI_QUAD_SIZE
])
521 float derivs
[3][2][TGSI_QUAD_SIZE
];
522 compute_gradient_1d(s
, t
, p
, derivs
);
523 return compute_lambda_1d_explicit_gradients(sview
, derivs
, 0);
528 compute_gradient_2d(const float s
[TGSI_QUAD_SIZE
],
529 const float t
[TGSI_QUAD_SIZE
],
530 const float p
[TGSI_QUAD_SIZE
],
531 float derivs
[3][2][TGSI_QUAD_SIZE
])
533 memset(derivs
, 0, 6 * TGSI_QUAD_SIZE
* sizeof(float));
534 derivs
[0][0][0] = s
[QUAD_BOTTOM_RIGHT
] - s
[QUAD_BOTTOM_LEFT
];
535 derivs
[0][1][0] = s
[QUAD_TOP_LEFT
] - s
[QUAD_BOTTOM_LEFT
];
536 derivs
[1][0][0] = t
[QUAD_BOTTOM_RIGHT
] - t
[QUAD_BOTTOM_LEFT
];
537 derivs
[1][1][0] = t
[QUAD_TOP_LEFT
] - t
[QUAD_BOTTOM_LEFT
];
541 compute_lambda_2d_explicit_gradients(const struct sp_sampler_view
*sview
,
542 const float derivs
[3][2][TGSI_QUAD_SIZE
],
545 const struct pipe_resource
*texture
= sview
->base
.texture
;
546 const float dsdx
= fabsf(derivs
[0][0][quad
]);
547 const float dsdy
= fabsf(derivs
[0][1][quad
]);
548 const float dtdx
= fabsf(derivs
[1][0][quad
]);
549 const float dtdy
= fabsf(derivs
[1][1][quad
]);
550 const float maxx
= MAX2(dsdx
, dsdy
) * u_minify(texture
->width0
, sview
->base
.u
.tex
.first_level
);
551 const float maxy
= MAX2(dtdx
, dtdy
) * u_minify(texture
->height0
, sview
->base
.u
.tex
.first_level
);
552 const float rho
= MAX2(maxx
, maxy
);
553 return util_fast_log2(rho
);
558 compute_lambda_2d(const struct sp_sampler_view
*sview
,
559 const float s
[TGSI_QUAD_SIZE
],
560 const float t
[TGSI_QUAD_SIZE
],
561 const float p
[TGSI_QUAD_SIZE
])
563 float derivs
[3][2][TGSI_QUAD_SIZE
];
564 compute_gradient_2d(s
, t
, p
, derivs
);
565 return compute_lambda_2d_explicit_gradients(sview
, derivs
, 0);
570 compute_gradient_3d(const float s
[TGSI_QUAD_SIZE
],
571 const float t
[TGSI_QUAD_SIZE
],
572 const float p
[TGSI_QUAD_SIZE
],
573 float derivs
[3][2][TGSI_QUAD_SIZE
])
575 memset(derivs
, 0, 6 * TGSI_QUAD_SIZE
* sizeof(float));
576 derivs
[0][0][0] = fabsf(s
[QUAD_BOTTOM_RIGHT
] - s
[QUAD_BOTTOM_LEFT
]);
577 derivs
[0][1][0] = fabsf(s
[QUAD_TOP_LEFT
] - s
[QUAD_BOTTOM_LEFT
]);
578 derivs
[1][0][0] = fabsf(t
[QUAD_BOTTOM_RIGHT
] - t
[QUAD_BOTTOM_LEFT
]);
579 derivs
[1][1][0] = fabsf(t
[QUAD_TOP_LEFT
] - t
[QUAD_BOTTOM_LEFT
]);
580 derivs
[2][0][0] = fabsf(p
[QUAD_BOTTOM_RIGHT
] - p
[QUAD_BOTTOM_LEFT
]);
581 derivs
[2][1][0] = fabsf(p
[QUAD_TOP_LEFT
] - p
[QUAD_BOTTOM_LEFT
]);
585 compute_lambda_3d_explicit_gradients(const struct sp_sampler_view
*sview
,
586 const float derivs
[3][2][TGSI_QUAD_SIZE
],
589 const struct pipe_resource
*texture
= sview
->base
.texture
;
590 const float dsdx
= fabsf(derivs
[0][0][quad
]);
591 const float dsdy
= fabsf(derivs
[0][1][quad
]);
592 const float dtdx
= fabsf(derivs
[1][0][quad
]);
593 const float dtdy
= fabsf(derivs
[1][1][quad
]);
594 const float dpdx
= fabsf(derivs
[2][0][quad
]);
595 const float dpdy
= fabsf(derivs
[2][1][quad
]);
596 const float maxx
= MAX2(dsdx
, dsdy
) * u_minify(texture
->width0
, sview
->base
.u
.tex
.first_level
);
597 const float maxy
= MAX2(dtdx
, dtdy
) * u_minify(texture
->height0
, sview
->base
.u
.tex
.first_level
);
598 const float maxz
= MAX2(dpdx
, dpdy
) * u_minify(texture
->depth0
, sview
->base
.u
.tex
.first_level
);
599 const float rho
= MAX3(maxx
, maxy
, maxz
);
601 return util_fast_log2(rho
);
606 compute_lambda_3d(const struct sp_sampler_view
*sview
,
607 const float s
[TGSI_QUAD_SIZE
],
608 const float t
[TGSI_QUAD_SIZE
],
609 const float p
[TGSI_QUAD_SIZE
])
611 float derivs
[3][2][TGSI_QUAD_SIZE
];
612 compute_gradient_3d(s
, t
, p
, derivs
);
613 return compute_lambda_3d_explicit_gradients(sview
, derivs
, 0);
618 compute_lambda_cube_explicit_gradients(const struct sp_sampler_view
*sview
,
619 const float derivs
[3][2][TGSI_QUAD_SIZE
],
622 const struct pipe_resource
*texture
= sview
->base
.texture
;
623 const float dsdx
= fabsf(derivs
[0][0][quad
]);
624 const float dsdy
= fabsf(derivs
[0][1][quad
]);
625 const float dtdx
= fabsf(derivs
[1][0][quad
]);
626 const float dtdy
= fabsf(derivs
[1][1][quad
]);
627 const float dpdx
= fabsf(derivs
[2][0][quad
]);
628 const float dpdy
= fabsf(derivs
[2][1][quad
]);
629 const float maxx
= MAX2(dsdx
, dsdy
);
630 const float maxy
= MAX2(dtdx
, dtdy
);
631 const float maxz
= MAX2(dpdx
, dpdy
);
632 const float rho
= MAX3(maxx
, maxy
, maxz
) * u_minify(texture
->width0
, sview
->base
.u
.tex
.first_level
) / 2.0f
;
634 return util_fast_log2(rho
);
638 compute_lambda_cube(const struct sp_sampler_view
*sview
,
639 const float s
[TGSI_QUAD_SIZE
],
640 const float t
[TGSI_QUAD_SIZE
],
641 const float p
[TGSI_QUAD_SIZE
])
643 float derivs
[3][2][TGSI_QUAD_SIZE
];
644 compute_gradient_3d(s
, t
, p
, derivs
);
645 return compute_lambda_cube_explicit_gradients(sview
, derivs
, 0);
649 * Compute lambda for a vertex texture sampler.
650 * Since there aren't derivatives to use, just return 0.
653 compute_lambda_vert(const struct sp_sampler_view
*sview
,
654 const float s
[TGSI_QUAD_SIZE
],
655 const float t
[TGSI_QUAD_SIZE
],
656 const float p
[TGSI_QUAD_SIZE
])
662 compute_lambda_from_grad_func
663 softpipe_get_lambda_from_grad_func(const struct pipe_sampler_view
*view
,
664 enum pipe_shader_type shader
)
666 switch (view
->target
) {
668 case PIPE_TEXTURE_1D
:
669 case PIPE_TEXTURE_1D_ARRAY
:
670 return compute_lambda_1d_explicit_gradients
;
671 case PIPE_TEXTURE_2D
:
672 case PIPE_TEXTURE_2D_ARRAY
:
673 case PIPE_TEXTURE_RECT
:
674 return compute_lambda_2d_explicit_gradients
;
675 case PIPE_TEXTURE_CUBE
:
676 case PIPE_TEXTURE_CUBE_ARRAY
:
677 return compute_lambda_cube_explicit_gradients
;
678 case PIPE_TEXTURE_3D
:
679 return compute_lambda_3d_explicit_gradients
;
682 return compute_lambda_1d_explicit_gradients
;
688 * Get a texel from a texture, using the texture tile cache.
690 * \param addr the template tex address containing cube, z, face info.
691 * \param x the x coord of texel within 2D image
692 * \param y the y coord of texel within 2D image
693 * \param rgba the quad to put the texel/color into
695 * XXX maybe move this into sp_tex_tile_cache.c and merge with the
696 * sp_get_cached_tile_tex() function.
701 static inline const float *
702 get_texel_buffer_no_border(const struct sp_sampler_view
*sp_sview
,
703 union tex_tile_address addr
, int x
, unsigned elmsize
)
705 const struct softpipe_tex_cached_tile
*tile
;
706 addr
.bits
.x
= x
* elmsize
/ TEX_TILE_SIZE
;
707 assert(x
* elmsize
/ TEX_TILE_SIZE
== addr
.bits
.x
);
709 x
%= TEX_TILE_SIZE
/ elmsize
;
711 tile
= sp_get_cached_tile_tex(sp_sview
->cache
, addr
);
713 return &tile
->data
.color
[0][x
][0];
717 static inline const float *
718 get_texel_2d_no_border(const struct sp_sampler_view
*sp_sview
,
719 union tex_tile_address addr
, int x
, int y
)
721 const struct softpipe_tex_cached_tile
*tile
;
722 addr
.bits
.x
= x
/ TEX_TILE_SIZE
;
723 addr
.bits
.y
= y
/ TEX_TILE_SIZE
;
727 tile
= sp_get_cached_tile_tex(sp_sview
->cache
, addr
);
729 return &tile
->data
.color
[y
][x
][0];
733 static inline const float *
734 get_texel_2d(const struct sp_sampler_view
*sp_sview
,
735 const struct sp_sampler
*sp_samp
,
736 union tex_tile_address addr
, int x
, int y
)
738 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
739 const unsigned level
= addr
.bits
.level
;
741 if (x
< 0 || x
>= (int) u_minify(texture
->width0
, level
) ||
742 y
< 0 || y
>= (int) u_minify(texture
->height0
, level
)) {
743 return sp_samp
->base
.border_color
.f
;
746 return get_texel_2d_no_border( sp_sview
, addr
, x
, y
);
752 * Here's the complete logic (HOLY CRAP) for finding next face and doing the
753 * corresponding coord wrapping, implemented by get_next_face,
754 * get_next_xcoord, get_next_ycoord.
755 * Read like that (first line):
756 * If face is +x and s coord is below zero, then
757 * new face is +z, new s is max , new t is old t
758 * (max is always cube size - 1).
760 * +x s- -> +z: s = max, t = t
761 * +x s+ -> -z: s = 0, t = t
762 * +x t- -> +y: s = max, t = max-s
763 * +x t+ -> -y: s = max, t = s
765 * -x s- -> -z: s = max, t = t
766 * -x s+ -> +z: s = 0, t = t
767 * -x t- -> +y: s = 0, t = s
768 * -x t+ -> -y: s = 0, t = max-s
770 * +y s- -> -x: s = t, t = 0
771 * +y s+ -> +x: s = max-t, t = 0
772 * +y t- -> -z: s = max-s, t = 0
773 * +y t+ -> +z: s = s, t = 0
775 * -y s- -> -x: s = max-t, t = max
776 * -y s+ -> +x: s = t, t = max
777 * -y t- -> +z: s = s, t = max
778 * -y t+ -> -z: s = max-s, t = max
780 * +z s- -> -x: s = max, t = t
781 * +z s+ -> +x: s = 0, t = t
782 * +z t- -> +y: s = s, t = max
783 * +z t+ -> -y: s = s, t = 0
785 * -z s- -> +x: s = max, t = t
786 * -z s+ -> -x: s = 0, t = t
787 * -z t- -> +y: s = max-s, t = 0
788 * -z t+ -> -y: s = max-s, t = max
793 * seamless cubemap neighbour array.
794 * this array is used to find the adjacent face in each of 4 directions,
795 * left, right, up, down. (or -x, +x, -y, +y).
797 static const unsigned face_array
[PIPE_TEX_FACE_MAX
][4] = {
798 /* pos X first then neg X is Z different, Y the same */
799 /* PIPE_TEX_FACE_POS_X,*/
800 { PIPE_TEX_FACE_POS_Z
, PIPE_TEX_FACE_NEG_Z
,
801 PIPE_TEX_FACE_POS_Y
, PIPE_TEX_FACE_NEG_Y
},
802 /* PIPE_TEX_FACE_NEG_X */
803 { PIPE_TEX_FACE_NEG_Z
, PIPE_TEX_FACE_POS_Z
,
804 PIPE_TEX_FACE_POS_Y
, PIPE_TEX_FACE_NEG_Y
},
806 /* pos Y first then neg Y is X different, X the same */
807 /* PIPE_TEX_FACE_POS_Y */
808 { PIPE_TEX_FACE_NEG_X
, PIPE_TEX_FACE_POS_X
,
809 PIPE_TEX_FACE_NEG_Z
, PIPE_TEX_FACE_POS_Z
},
811 /* PIPE_TEX_FACE_NEG_Y */
812 { PIPE_TEX_FACE_NEG_X
, PIPE_TEX_FACE_POS_X
,
813 PIPE_TEX_FACE_POS_Z
, PIPE_TEX_FACE_NEG_Z
},
815 /* pos Z first then neg Y is X different, X the same */
816 /* PIPE_TEX_FACE_POS_Z */
817 { PIPE_TEX_FACE_NEG_X
, PIPE_TEX_FACE_POS_X
,
818 PIPE_TEX_FACE_POS_Y
, PIPE_TEX_FACE_NEG_Y
},
820 /* PIPE_TEX_FACE_NEG_Z */
821 { PIPE_TEX_FACE_POS_X
, PIPE_TEX_FACE_NEG_X
,
822 PIPE_TEX_FACE_POS_Y
, PIPE_TEX_FACE_NEG_Y
}
825 static inline unsigned
826 get_next_face(unsigned face
, int idx
)
828 return face_array
[face
][idx
];
832 * return a new xcoord based on old face, old coords, cube size
833 * and fall_off_index (0 for x-, 1 for x+, 2 for y-, 3 for y+)
836 get_next_xcoord(unsigned face
, unsigned fall_off_index
, int max
, int xc
, int yc
)
838 if ((face
== 0 && fall_off_index
!= 1) ||
839 (face
== 1 && fall_off_index
== 0) ||
840 (face
== 4 && fall_off_index
== 0) ||
841 (face
== 5 && fall_off_index
== 0)) {
844 if ((face
== 1 && fall_off_index
!= 0) ||
845 (face
== 0 && fall_off_index
== 1) ||
846 (face
== 4 && fall_off_index
== 1) ||
847 (face
== 5 && fall_off_index
== 1)) {
850 if ((face
== 4 && fall_off_index
>= 2) ||
851 (face
== 2 && fall_off_index
== 3) ||
852 (face
== 3 && fall_off_index
== 2)) {
855 if ((face
== 5 && fall_off_index
>= 2) ||
856 (face
== 2 && fall_off_index
== 2) ||
857 (face
== 3 && fall_off_index
== 3)) {
860 if ((face
== 2 && fall_off_index
== 0) ||
861 (face
== 3 && fall_off_index
== 1)) {
864 /* (face == 2 && fall_off_index == 1) ||
865 (face == 3 && fall_off_index == 0)) */
870 * return a new ycoord based on old face, old coords, cube size
871 * and fall_off_index (0 for x-, 1 for x+, 2 for y-, 3 for y+)
874 get_next_ycoord(unsigned face
, unsigned fall_off_index
, int max
, int xc
, int yc
)
876 if ((fall_off_index
<= 1) && (face
<= 1 || face
>= 4)) {
880 (face
== 4 && fall_off_index
== 3) ||
881 (face
== 5 && fall_off_index
== 2)) {
885 (face
== 4 && fall_off_index
== 2) ||
886 (face
== 5 && fall_off_index
== 3)) {
889 if ((face
== 0 && fall_off_index
== 3) ||
890 (face
== 1 && fall_off_index
== 2)) {
893 /* (face == 0 && fall_off_index == 2) ||
894 (face == 1 && fall_off_index == 3) */
899 /* Gather a quad of adjacent texels within a tile:
902 get_texel_quad_2d_no_border_single_tile(const struct sp_sampler_view
*sp_sview
,
903 union tex_tile_address addr
,
904 unsigned x
, unsigned y
,
907 const struct softpipe_tex_cached_tile
*tile
;
909 addr
.bits
.x
= x
/ TEX_TILE_SIZE
;
910 addr
.bits
.y
= y
/ TEX_TILE_SIZE
;
914 tile
= sp_get_cached_tile_tex(sp_sview
->cache
, addr
);
916 out
[0] = &tile
->data
.color
[y
][x
][0];
917 out
[1] = &tile
->data
.color
[y
][x
+1][0];
918 out
[2] = &tile
->data
.color
[y
+1][x
][0];
919 out
[3] = &tile
->data
.color
[y
+1][x
+1][0];
923 /* Gather a quad of potentially non-adjacent texels:
926 get_texel_quad_2d_no_border(const struct sp_sampler_view
*sp_sview
,
927 union tex_tile_address addr
,
932 out
[0] = get_texel_2d_no_border( sp_sview
, addr
, x0
, y0
);
933 out
[1] = get_texel_2d_no_border( sp_sview
, addr
, x1
, y0
);
934 out
[2] = get_texel_2d_no_border( sp_sview
, addr
, x0
, y1
);
935 out
[3] = get_texel_2d_no_border( sp_sview
, addr
, x1
, y1
);
941 static inline const float *
942 get_texel_3d_no_border(const struct sp_sampler_view
*sp_sview
,
943 union tex_tile_address addr
, int x
, int y
, int z
)
945 const struct softpipe_tex_cached_tile
*tile
;
947 addr
.bits
.x
= x
/ TEX_TILE_SIZE
;
948 addr
.bits
.y
= y
/ TEX_TILE_SIZE
;
953 tile
= sp_get_cached_tile_tex(sp_sview
->cache
, addr
);
955 return &tile
->data
.color
[y
][x
][0];
959 static inline const float *
960 get_texel_3d(const struct sp_sampler_view
*sp_sview
,
961 const struct sp_sampler
*sp_samp
,
962 union tex_tile_address addr
, int x
, int y
, int z
)
964 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
965 const unsigned level
= addr
.bits
.level
;
967 if (x
< 0 || x
>= (int) u_minify(texture
->width0
, level
) ||
968 y
< 0 || y
>= (int) u_minify(texture
->height0
, level
) ||
969 z
< 0 || z
>= (int) u_minify(texture
->depth0
, level
)) {
970 return sp_samp
->base
.border_color
.f
;
973 return get_texel_3d_no_border( sp_sview
, addr
, x
, y
, z
);
978 /* Get texel pointer for 1D array texture */
979 static inline const float *
980 get_texel_1d_array(const struct sp_sampler_view
*sp_sview
,
981 const struct sp_sampler
*sp_samp
,
982 union tex_tile_address addr
, int x
, int y
)
984 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
985 const unsigned level
= addr
.bits
.level
;
987 if (x
< 0 || x
>= (int) u_minify(texture
->width0
, level
)) {
988 return sp_samp
->base
.border_color
.f
;
991 return get_texel_2d_no_border(sp_sview
, addr
, x
, y
);
996 /* Get texel pointer for 2D array texture */
997 static inline const float *
998 get_texel_2d_array(const struct sp_sampler_view
*sp_sview
,
999 const struct sp_sampler
*sp_samp
,
1000 union tex_tile_address addr
, int x
, int y
, int layer
)
1002 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
1003 const unsigned level
= addr
.bits
.level
;
1005 assert(layer
< (int) texture
->array_size
);
1008 if (x
< 0 || x
>= (int) u_minify(texture
->width0
, level
) ||
1009 y
< 0 || y
>= (int) u_minify(texture
->height0
, level
)) {
1010 return sp_samp
->base
.border_color
.f
;
1013 return get_texel_3d_no_border(sp_sview
, addr
, x
, y
, layer
);
1018 static inline const float *
1019 get_texel_cube_seamless(const struct sp_sampler_view
*sp_sview
,
1020 union tex_tile_address addr
, int x
, int y
,
1021 float *corner
, int layer
, unsigned face
)
1023 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
1024 const unsigned level
= addr
.bits
.level
;
1025 int new_x
, new_y
, max_x
;
1027 max_x
= (int) u_minify(texture
->width0
, level
);
1029 assert(texture
->width0
== texture
->height0
);
1033 /* change the face */
1036 * Cheat with corners. They are difficult and I believe because we don't get
1037 * per-pixel faces we can actually have multiple corner texels per pixel,
1038 * which screws things up majorly in any case (as the per spec behavior is
1039 * to average the 3 remaining texels, which we might not have).
1040 * Hence just make sure that the 2nd coord is clamped, will simply pick the
1041 * sample which would have fallen off the x coord, but not y coord.
1042 * So the filter weight of the samples will be wrong, but at least this
1043 * ensures that only valid texels near the corner are used.
1045 if (y
< 0 || y
>= max_x
) {
1046 y
= CLAMP(y
, 0, max_x
- 1);
1048 new_x
= get_next_xcoord(face
, 0, max_x
-1, x
, y
);
1049 new_y
= get_next_ycoord(face
, 0, max_x
-1, x
, y
);
1050 face
= get_next_face(face
, 0);
1051 } else if (x
>= max_x
) {
1052 if (y
< 0 || y
>= max_x
) {
1053 y
= CLAMP(y
, 0, max_x
- 1);
1055 new_x
= get_next_xcoord(face
, 1, max_x
-1, x
, y
);
1056 new_y
= get_next_ycoord(face
, 1, max_x
-1, x
, y
);
1057 face
= get_next_face(face
, 1);
1059 new_x
= get_next_xcoord(face
, 2, max_x
-1, x
, y
);
1060 new_y
= get_next_ycoord(face
, 2, max_x
-1, x
, y
);
1061 face
= get_next_face(face
, 2);
1062 } else if (y
>= max_x
) {
1063 new_x
= get_next_xcoord(face
, 3, max_x
-1, x
, y
);
1064 new_y
= get_next_ycoord(face
, 3, max_x
-1, x
, y
);
1065 face
= get_next_face(face
, 3);
1068 return get_texel_3d_no_border(sp_sview
, addr
, new_x
, new_y
, layer
+ face
);
1072 /* Get texel pointer for cube array texture */
1073 static inline const float *
1074 get_texel_cube_array(const struct sp_sampler_view
*sp_sview
,
1075 const struct sp_sampler
*sp_samp
,
1076 union tex_tile_address addr
, int x
, int y
, int layer
)
1078 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
1079 const unsigned level
= addr
.bits
.level
;
1081 assert(layer
< (int) texture
->array_size
);
1084 if (x
< 0 || x
>= (int) u_minify(texture
->width0
, level
) ||
1085 y
< 0 || y
>= (int) u_minify(texture
->height0
, level
)) {
1086 return sp_samp
->base
.border_color
.f
;
1089 return get_texel_3d_no_border(sp_sview
, addr
, x
, y
, layer
);
1093 * Given the logbase2 of a mipmap's base level size and a mipmap level,
1094 * return the size (in texels) of that mipmap level.
1095 * For example, if level[0].width = 256 then base_pot will be 8.
1096 * If level = 2, then we'll return 64 (the width at level=2).
1097 * Return 1 if level > base_pot.
1099 static inline unsigned
1100 pot_level_size(unsigned base_pot
, unsigned level
)
1102 return (base_pot
>= level
) ? (1 << (base_pot
- level
)) : 1;
1107 print_sample(const char *function
, const float *rgba
)
1109 debug_printf("%s %g %g %g %g\n",
1111 rgba
[0], rgba
[TGSI_NUM_CHANNELS
], rgba
[2*TGSI_NUM_CHANNELS
], rgba
[3*TGSI_NUM_CHANNELS
]);
1116 print_sample_4(const char *function
, float rgba
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
])
1118 debug_printf("%s %g %g %g %g, %g %g %g %g, %g %g %g %g, %g %g %g %g\n",
1120 rgba
[0][0], rgba
[1][0], rgba
[2][0], rgba
[3][0],
1121 rgba
[0][1], rgba
[1][1], rgba
[2][1], rgba
[3][1],
1122 rgba
[0][2], rgba
[1][2], rgba
[2][2], rgba
[3][2],
1123 rgba
[0][3], rgba
[1][3], rgba
[2][3], rgba
[3][3]);
1127 /* Some image-filter fastpaths:
1130 img_filter_2d_linear_repeat_POT(const struct sp_sampler_view
*sp_sview
,
1131 const struct sp_sampler
*sp_samp
,
1132 const struct img_filter_args
*args
,
1135 const unsigned xpot
= pot_level_size(sp_sview
->xpot
, args
->level
);
1136 const unsigned ypot
= pot_level_size(sp_sview
->ypot
, args
->level
);
1137 const int xmax
= (xpot
- 1) & (TEX_TILE_SIZE
- 1); /* MIN2(TEX_TILE_SIZE, xpot) - 1; */
1138 const int ymax
= (ypot
- 1) & (TEX_TILE_SIZE
- 1); /* MIN2(TEX_TILE_SIZE, ypot) - 1; */
1139 union tex_tile_address addr
;
1142 const float u
= (args
->s
* xpot
- 0.5F
) + args
->offset
[0];
1143 const float v
= (args
->t
* ypot
- 0.5F
) + args
->offset
[1];
1145 const int uflr
= util_ifloor(u
);
1146 const int vflr
= util_ifloor(v
);
1148 const float xw
= u
- (float)uflr
;
1149 const float yw
= v
- (float)vflr
;
1151 const int x0
= uflr
& (xpot
- 1);
1152 const int y0
= vflr
& (ypot
- 1);
1157 addr
.bits
.level
= args
->level
;
1158 addr
.bits
.z
= sp_sview
->base
.u
.tex
.first_layer
;
1160 /* Can we fetch all four at once:
1162 if (x0
< xmax
&& y0
< ymax
) {
1163 get_texel_quad_2d_no_border_single_tile(sp_sview
, addr
, x0
, y0
, tx
);
1166 const unsigned x1
= (x0
+ 1) & (xpot
- 1);
1167 const unsigned y1
= (y0
+ 1) & (ypot
- 1);
1168 get_texel_quad_2d_no_border(sp_sview
, addr
, x0
, y0
, x1
, y1
, tx
);
1171 /* interpolate R, G, B, A */
1172 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++) {
1173 rgba
[TGSI_NUM_CHANNELS
*c
] = lerp_2d(xw
, yw
,
1175 tx
[2][c
], tx
[3][c
]);
1179 print_sample(__FUNCTION__
, rgba
);
1185 img_filter_2d_nearest_repeat_POT(const struct sp_sampler_view
*sp_sview
,
1186 const struct sp_sampler
*sp_samp
,
1187 const struct img_filter_args
*args
,
1190 const unsigned xpot
= pot_level_size(sp_sview
->xpot
, args
->level
);
1191 const unsigned ypot
= pot_level_size(sp_sview
->ypot
, args
->level
);
1193 union tex_tile_address addr
;
1196 const float u
= args
->s
* xpot
+ args
->offset
[0];
1197 const float v
= args
->t
* ypot
+ args
->offset
[1];
1199 const int uflr
= util_ifloor(u
);
1200 const int vflr
= util_ifloor(v
);
1202 const int x0
= uflr
& (xpot
- 1);
1203 const int y0
= vflr
& (ypot
- 1);
1206 addr
.bits
.level
= args
->level
;
1207 addr
.bits
.z
= sp_sview
->base
.u
.tex
.first_layer
;
1209 out
= get_texel_2d_no_border(sp_sview
, addr
, x0
, y0
);
1210 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1211 rgba
[TGSI_NUM_CHANNELS
*c
] = out
[c
];
1214 print_sample(__FUNCTION__
, rgba
);
1220 img_filter_2d_nearest_clamp_POT(const struct sp_sampler_view
*sp_sview
,
1221 const struct sp_sampler
*sp_samp
,
1222 const struct img_filter_args
*args
,
1225 const unsigned xpot
= pot_level_size(sp_sview
->xpot
, args
->level
);
1226 const unsigned ypot
= pot_level_size(sp_sview
->ypot
, args
->level
);
1227 union tex_tile_address addr
;
1230 const float u
= args
->s
* xpot
+ args
->offset
[0];
1231 const float v
= args
->t
* ypot
+ args
->offset
[1];
1237 addr
.bits
.level
= args
->level
;
1238 addr
.bits
.z
= sp_sview
->base
.u
.tex
.first_layer
;
1240 x0
= util_ifloor(u
);
1243 else if (x0
> (int) xpot
- 1)
1246 y0
= util_ifloor(v
);
1249 else if (y0
> (int) ypot
- 1)
1252 out
= get_texel_2d_no_border(sp_sview
, addr
, x0
, y0
);
1253 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1254 rgba
[TGSI_NUM_CHANNELS
*c
] = out
[c
];
1257 print_sample(__FUNCTION__
, rgba
);
1263 img_filter_1d_nearest(const struct sp_sampler_view
*sp_sview
,
1264 const struct sp_sampler
*sp_samp
,
1265 const struct img_filter_args
*args
,
1268 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
1269 const int width
= u_minify(texture
->width0
, args
->level
);
1271 union tex_tile_address addr
;
1278 addr
.bits
.level
= args
->level
;
1280 sp_samp
->nearest_texcoord_s(args
->s
, width
, args
->offset
[0], &x
);
1282 out
= get_texel_1d_array(sp_sview
, sp_samp
, addr
, x
,
1283 sp_sview
->base
.u
.tex
.first_layer
);
1284 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1285 rgba
[TGSI_NUM_CHANNELS
*c
] = out
[c
];
1288 print_sample(__FUNCTION__
, rgba
);
1294 img_filter_1d_array_nearest(const struct sp_sampler_view
*sp_sview
,
1295 const struct sp_sampler
*sp_samp
,
1296 const struct img_filter_args
*args
,
1299 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
1300 const int width
= u_minify(texture
->width0
, args
->level
);
1301 const int layer
= coord_to_layer(args
->t
, sp_sview
->base
.u
.tex
.first_layer
,
1302 sp_sview
->base
.u
.tex
.last_layer
);
1304 union tex_tile_address addr
;
1311 addr
.bits
.level
= args
->level
;
1313 sp_samp
->nearest_texcoord_s(args
->s
, width
, args
->offset
[0], &x
);
1315 out
= get_texel_1d_array(sp_sview
, sp_samp
, addr
, x
, layer
);
1316 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1317 rgba
[TGSI_NUM_CHANNELS
*c
] = out
[c
];
1320 print_sample(__FUNCTION__
, rgba
);
1326 img_filter_2d_nearest(const struct sp_sampler_view
*sp_sview
,
1327 const struct sp_sampler
*sp_samp
,
1328 const struct img_filter_args
*args
,
1331 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
1332 const int width
= u_minify(texture
->width0
, args
->level
);
1333 const int height
= u_minify(texture
->height0
, args
->level
);
1335 union tex_tile_address addr
;
1343 addr
.bits
.level
= args
->level
;
1344 addr
.bits
.z
= sp_sview
->base
.u
.tex
.first_layer
;
1346 sp_samp
->nearest_texcoord_s(args
->s
, width
, args
->offset
[0], &x
);
1347 sp_samp
->nearest_texcoord_t(args
->t
, height
, args
->offset
[1], &y
);
1349 out
= get_texel_2d(sp_sview
, sp_samp
, addr
, x
, y
);
1350 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1351 rgba
[TGSI_NUM_CHANNELS
*c
] = out
[c
];
1354 print_sample(__FUNCTION__
, rgba
);
1360 img_filter_2d_array_nearest(const struct sp_sampler_view
*sp_sview
,
1361 const struct sp_sampler
*sp_samp
,
1362 const struct img_filter_args
*args
,
1365 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
1366 const int width
= u_minify(texture
->width0
, args
->level
);
1367 const int height
= u_minify(texture
->height0
, args
->level
);
1368 const int layer
= coord_to_layer(args
->p
, sp_sview
->base
.u
.tex
.first_layer
,
1369 sp_sview
->base
.u
.tex
.last_layer
);
1371 union tex_tile_address addr
;
1379 addr
.bits
.level
= args
->level
;
1381 sp_samp
->nearest_texcoord_s(args
->s
, width
, args
->offset
[0], &x
);
1382 sp_samp
->nearest_texcoord_t(args
->t
, height
, args
->offset
[1], &y
);
1384 out
= get_texel_2d_array(sp_sview
, sp_samp
, addr
, x
, y
, layer
);
1385 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1386 rgba
[TGSI_NUM_CHANNELS
*c
] = out
[c
];
1389 print_sample(__FUNCTION__
, rgba
);
1395 img_filter_cube_nearest(const struct sp_sampler_view
*sp_sview
,
1396 const struct sp_sampler
*sp_samp
,
1397 const struct img_filter_args
*args
,
1400 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
1401 const int width
= u_minify(texture
->width0
, args
->level
);
1402 const int height
= u_minify(texture
->height0
, args
->level
);
1403 const int layerface
= args
->face_id
+ sp_sview
->base
.u
.tex
.first_layer
;
1405 union tex_tile_address addr
;
1413 addr
.bits
.level
= args
->level
;
1416 * If NEAREST filtering is done within a miplevel, always apply wrap
1417 * mode CLAMP_TO_EDGE.
1419 if (sp_samp
->base
.seamless_cube_map
) {
1420 wrap_nearest_clamp_to_edge(args
->s
, width
, args
->offset
[0], &x
);
1421 wrap_nearest_clamp_to_edge(args
->t
, height
, args
->offset
[1], &y
);
1423 /* Would probably make sense to ignore mode and just do edge clamp */
1424 sp_samp
->nearest_texcoord_s(args
->s
, width
, args
->offset
[0], &x
);
1425 sp_samp
->nearest_texcoord_t(args
->t
, height
, args
->offset
[1], &y
);
1428 out
= get_texel_cube_array(sp_sview
, sp_samp
, addr
, x
, y
, layerface
);
1429 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1430 rgba
[TGSI_NUM_CHANNELS
*c
] = out
[c
];
1433 print_sample(__FUNCTION__
, rgba
);
1438 img_filter_cube_array_nearest(const struct sp_sampler_view
*sp_sview
,
1439 const struct sp_sampler
*sp_samp
,
1440 const struct img_filter_args
*args
,
1443 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
1444 const int width
= u_minify(texture
->width0
, args
->level
);
1445 const int height
= u_minify(texture
->height0
, args
->level
);
1446 const int layerface
=
1447 coord_to_layer(6 * args
->p
+ sp_sview
->base
.u
.tex
.first_layer
,
1448 sp_sview
->base
.u
.tex
.first_layer
,
1449 sp_sview
->base
.u
.tex
.last_layer
- 5) + args
->face_id
;
1451 union tex_tile_address addr
;
1459 addr
.bits
.level
= args
->level
;
1461 sp_samp
->nearest_texcoord_s(args
->s
, width
, args
->offset
[0], &x
);
1462 sp_samp
->nearest_texcoord_t(args
->t
, height
, args
->offset
[1], &y
);
1464 out
= get_texel_cube_array(sp_sview
, sp_samp
, addr
, x
, y
, layerface
);
1465 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1466 rgba
[TGSI_NUM_CHANNELS
*c
] = out
[c
];
1469 print_sample(__FUNCTION__
, rgba
);
1474 img_filter_3d_nearest(const struct sp_sampler_view
*sp_sview
,
1475 const struct sp_sampler
*sp_samp
,
1476 const struct img_filter_args
*args
,
1479 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
1480 const int width
= u_minify(texture
->width0
, args
->level
);
1481 const int height
= u_minify(texture
->height0
, args
->level
);
1482 const int depth
= u_minify(texture
->depth0
, args
->level
);
1484 union tex_tile_address addr
;
1492 sp_samp
->nearest_texcoord_s(args
->s
, width
, args
->offset
[0], &x
);
1493 sp_samp
->nearest_texcoord_t(args
->t
, height
, args
->offset
[1], &y
);
1494 sp_samp
->nearest_texcoord_p(args
->p
, depth
, args
->offset
[2], &z
);
1497 addr
.bits
.level
= args
->level
;
1499 out
= get_texel_3d(sp_sview
, sp_samp
, addr
, x
, y
, z
);
1500 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1501 rgba
[TGSI_NUM_CHANNELS
*c
] = out
[c
];
1506 img_filter_1d_linear(const struct sp_sampler_view
*sp_sview
,
1507 const struct sp_sampler
*sp_samp
,
1508 const struct img_filter_args
*args
,
1511 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
1512 const int width
= u_minify(texture
->width0
, args
->level
);
1514 float xw
; /* weights */
1515 union tex_tile_address addr
;
1516 const float *tx0
, *tx1
;
1522 addr
.bits
.level
= args
->level
;
1524 sp_samp
->linear_texcoord_s(args
->s
, width
, args
->offset
[0], &x0
, &x1
, &xw
);
1526 tx0
= get_texel_1d_array(sp_sview
, sp_samp
, addr
, x0
,
1527 sp_sview
->base
.u
.tex
.first_layer
);
1528 tx1
= get_texel_1d_array(sp_sview
, sp_samp
, addr
, x1
,
1529 sp_sview
->base
.u
.tex
.first_layer
);
1531 /* interpolate R, G, B, A */
1532 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1533 rgba
[TGSI_NUM_CHANNELS
*c
] = lerp(xw
, tx0
[c
], tx1
[c
]);
1538 img_filter_1d_array_linear(const struct sp_sampler_view
*sp_sview
,
1539 const struct sp_sampler
*sp_samp
,
1540 const struct img_filter_args
*args
,
1543 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
1544 const int width
= u_minify(texture
->width0
, args
->level
);
1545 const int layer
= coord_to_layer(args
->t
, sp_sview
->base
.u
.tex
.first_layer
,
1546 sp_sview
->base
.u
.tex
.last_layer
);
1548 float xw
; /* weights */
1549 union tex_tile_address addr
;
1550 const float *tx0
, *tx1
;
1556 addr
.bits
.level
= args
->level
;
1558 sp_samp
->linear_texcoord_s(args
->s
, width
, args
->offset
[0], &x0
, &x1
, &xw
);
1560 tx0
= get_texel_1d_array(sp_sview
, sp_samp
, addr
, x0
, layer
);
1561 tx1
= get_texel_1d_array(sp_sview
, sp_samp
, addr
, x1
, layer
);
1563 /* interpolate R, G, B, A */
1564 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1565 rgba
[TGSI_NUM_CHANNELS
*c
] = lerp(xw
, tx0
[c
], tx1
[c
]);
1569 * Retrieve the gathered value, need to convert to the
1570 * TGSI expected interface, and take component select
1571 * and swizzling into account.
1574 get_gather_value(const struct sp_sampler_view
*sp_sview
,
1575 int chan_in
, int comp_sel
,
1582 * softpipe samples in a different order
1583 * to TGSI expects, so we need to swizzle,
1584 * the samples into the correct slots.
1604 /* pick which component to use for the swizzle */
1607 swizzle
= sp_sview
->base
.swizzle_r
;
1610 swizzle
= sp_sview
->base
.swizzle_g
;
1613 swizzle
= sp_sview
->base
.swizzle_b
;
1616 swizzle
= sp_sview
->base
.swizzle_a
;
1623 /* get correct result using the channel and swizzle */
1625 case PIPE_SWIZZLE_0
:
1627 case PIPE_SWIZZLE_1
:
1630 return tx
[chan
][swizzle
];
1636 img_filter_2d_linear(const struct sp_sampler_view
*sp_sview
,
1637 const struct sp_sampler
*sp_samp
,
1638 const struct img_filter_args
*args
,
1641 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
1642 const int width
= u_minify(texture
->width0
, args
->level
);
1643 const int height
= u_minify(texture
->height0
, args
->level
);
1645 float xw
, yw
; /* weights */
1646 union tex_tile_address addr
;
1654 addr
.bits
.level
= args
->level
;
1655 addr
.bits
.z
= sp_sview
->base
.u
.tex
.first_layer
;
1657 sp_samp
->linear_texcoord_s(args
->s
, width
, args
->offset
[0], &x0
, &x1
, &xw
);
1658 sp_samp
->linear_texcoord_t(args
->t
, height
, args
->offset
[1], &y0
, &y1
, &yw
);
1660 tx
[0] = get_texel_2d(sp_sview
, sp_samp
, addr
, x0
, y0
);
1661 tx
[1] = get_texel_2d(sp_sview
, sp_samp
, addr
, x1
, y0
);
1662 tx
[2] = get_texel_2d(sp_sview
, sp_samp
, addr
, x0
, y1
);
1663 tx
[3] = get_texel_2d(sp_sview
, sp_samp
, addr
, x1
, y1
);
1665 if (args
->gather_only
) {
1666 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1667 rgba
[TGSI_NUM_CHANNELS
*c
] = get_gather_value(sp_sview
, c
,
1671 /* interpolate R, G, B, A */
1672 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1673 rgba
[TGSI_NUM_CHANNELS
*c
] = lerp_2d(xw
, yw
,
1675 tx
[2][c
], tx
[3][c
]);
1681 img_filter_2d_array_linear(const struct sp_sampler_view
*sp_sview
,
1682 const struct sp_sampler
*sp_samp
,
1683 const struct img_filter_args
*args
,
1686 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
1687 const int width
= u_minify(texture
->width0
, args
->level
);
1688 const int height
= u_minify(texture
->height0
, args
->level
);
1689 const int layer
= coord_to_layer(args
->p
, sp_sview
->base
.u
.tex
.first_layer
,
1690 sp_sview
->base
.u
.tex
.last_layer
);
1692 float xw
, yw
; /* weights */
1693 union tex_tile_address addr
;
1701 addr
.bits
.level
= args
->level
;
1703 sp_samp
->linear_texcoord_s(args
->s
, width
, args
->offset
[0], &x0
, &x1
, &xw
);
1704 sp_samp
->linear_texcoord_t(args
->t
, height
, args
->offset
[1], &y0
, &y1
, &yw
);
1706 tx
[0] = get_texel_2d_array(sp_sview
, sp_samp
, addr
, x0
, y0
, layer
);
1707 tx
[1] = get_texel_2d_array(sp_sview
, sp_samp
, addr
, x1
, y0
, layer
);
1708 tx
[2] = get_texel_2d_array(sp_sview
, sp_samp
, addr
, x0
, y1
, layer
);
1709 tx
[3] = get_texel_2d_array(sp_sview
, sp_samp
, addr
, x1
, y1
, layer
);
1711 if (args
->gather_only
) {
1712 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1713 rgba
[TGSI_NUM_CHANNELS
*c
] = get_gather_value(sp_sview
, c
,
1717 /* interpolate R, G, B, A */
1718 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1719 rgba
[TGSI_NUM_CHANNELS
*c
] = lerp_2d(xw
, yw
,
1721 tx
[2][c
], tx
[3][c
]);
1727 img_filter_cube_linear(const struct sp_sampler_view
*sp_sview
,
1728 const struct sp_sampler
*sp_samp
,
1729 const struct img_filter_args
*args
,
1732 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
1733 const int width
= u_minify(texture
->width0
, args
->level
);
1734 const int height
= u_minify(texture
->height0
, args
->level
);
1735 const int layer
= sp_sview
->base
.u
.tex
.first_layer
;
1737 float xw
, yw
; /* weights */
1738 union tex_tile_address addr
;
1740 float corner0
[TGSI_QUAD_SIZE
], corner1
[TGSI_QUAD_SIZE
],
1741 corner2
[TGSI_QUAD_SIZE
], corner3
[TGSI_QUAD_SIZE
];
1748 addr
.bits
.level
= args
->level
;
1751 * For seamless if LINEAR filtering is done within a miplevel,
1752 * always apply wrap mode CLAMP_TO_BORDER.
1754 if (sp_samp
->base
.seamless_cube_map
) {
1755 /* Note this is a bit overkill, actual clamping is not required */
1756 wrap_linear_clamp_to_border(args
->s
, width
, args
->offset
[0], &x0
, &x1
, &xw
);
1757 wrap_linear_clamp_to_border(args
->t
, height
, args
->offset
[1], &y0
, &y1
, &yw
);
1759 /* Would probably make sense to ignore mode and just do edge clamp */
1760 sp_samp
->linear_texcoord_s(args
->s
, width
, args
->offset
[0], &x0
, &x1
, &xw
);
1761 sp_samp
->linear_texcoord_t(args
->t
, height
, args
->offset
[1], &y0
, &y1
, &yw
);
1764 if (sp_samp
->base
.seamless_cube_map
) {
1765 tx
[0] = get_texel_cube_seamless(sp_sview
, addr
, x0
, y0
, corner0
, layer
, args
->face_id
);
1766 tx
[1] = get_texel_cube_seamless(sp_sview
, addr
, x1
, y0
, corner1
, layer
, args
->face_id
);
1767 tx
[2] = get_texel_cube_seamless(sp_sview
, addr
, x0
, y1
, corner2
, layer
, args
->face_id
);
1768 tx
[3] = get_texel_cube_seamless(sp_sview
, addr
, x1
, y1
, corner3
, layer
, args
->face_id
);
1770 tx
[0] = get_texel_cube_array(sp_sview
, sp_samp
, addr
, x0
, y0
, layer
+ args
->face_id
);
1771 tx
[1] = get_texel_cube_array(sp_sview
, sp_samp
, addr
, x1
, y0
, layer
+ args
->face_id
);
1772 tx
[2] = get_texel_cube_array(sp_sview
, sp_samp
, addr
, x0
, y1
, layer
+ args
->face_id
);
1773 tx
[3] = get_texel_cube_array(sp_sview
, sp_samp
, addr
, x1
, y1
, layer
+ args
->face_id
);
1776 if (args
->gather_only
) {
1777 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1778 rgba
[TGSI_NUM_CHANNELS
*c
] = get_gather_value(sp_sview
, c
,
1782 /* interpolate R, G, B, A */
1783 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1784 rgba
[TGSI_NUM_CHANNELS
*c
] = lerp_2d(xw
, yw
,
1786 tx
[2][c
], tx
[3][c
]);
1792 img_filter_cube_array_linear(const struct sp_sampler_view
*sp_sview
,
1793 const struct sp_sampler
*sp_samp
,
1794 const struct img_filter_args
*args
,
1797 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
1798 const int width
= u_minify(texture
->width0
, args
->level
);
1799 const int height
= u_minify(texture
->height0
, args
->level
);
1801 coord_to_layer(6 * args
->p
+ sp_sview
->base
.u
.tex
.first_layer
,
1802 sp_sview
->base
.u
.tex
.first_layer
,
1803 sp_sview
->base
.u
.tex
.last_layer
- 5);
1805 float xw
, yw
; /* weights */
1806 union tex_tile_address addr
;
1808 float corner0
[TGSI_QUAD_SIZE
], corner1
[TGSI_QUAD_SIZE
],
1809 corner2
[TGSI_QUAD_SIZE
], corner3
[TGSI_QUAD_SIZE
];
1816 addr
.bits
.level
= args
->level
;
1819 * For seamless if LINEAR filtering is done within a miplevel,
1820 * always apply wrap mode CLAMP_TO_BORDER.
1822 if (sp_samp
->base
.seamless_cube_map
) {
1823 /* Note this is a bit overkill, actual clamping is not required */
1824 wrap_linear_clamp_to_border(args
->s
, width
, args
->offset
[0], &x0
, &x1
, &xw
);
1825 wrap_linear_clamp_to_border(args
->t
, height
, args
->offset
[1], &y0
, &y1
, &yw
);
1827 /* Would probably make sense to ignore mode and just do edge clamp */
1828 sp_samp
->linear_texcoord_s(args
->s
, width
, args
->offset
[0], &x0
, &x1
, &xw
);
1829 sp_samp
->linear_texcoord_t(args
->t
, height
, args
->offset
[1], &y0
, &y1
, &yw
);
1832 if (sp_samp
->base
.seamless_cube_map
) {
1833 tx
[0] = get_texel_cube_seamless(sp_sview
, addr
, x0
, y0
, corner0
, layer
, args
->face_id
);
1834 tx
[1] = get_texel_cube_seamless(sp_sview
, addr
, x1
, y0
, corner1
, layer
, args
->face_id
);
1835 tx
[2] = get_texel_cube_seamless(sp_sview
, addr
, x0
, y1
, corner2
, layer
, args
->face_id
);
1836 tx
[3] = get_texel_cube_seamless(sp_sview
, addr
, x1
, y1
, corner3
, layer
, args
->face_id
);
1838 tx
[0] = get_texel_cube_array(sp_sview
, sp_samp
, addr
, x0
, y0
, layer
+ args
->face_id
);
1839 tx
[1] = get_texel_cube_array(sp_sview
, sp_samp
, addr
, x1
, y0
, layer
+ args
->face_id
);
1840 tx
[2] = get_texel_cube_array(sp_sview
, sp_samp
, addr
, x0
, y1
, layer
+ args
->face_id
);
1841 tx
[3] = get_texel_cube_array(sp_sview
, sp_samp
, addr
, x1
, y1
, layer
+ args
->face_id
);
1844 if (args
->gather_only
) {
1845 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1846 rgba
[TGSI_NUM_CHANNELS
*c
] = get_gather_value(sp_sview
, c
,
1850 /* interpolate R, G, B, A */
1851 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1852 rgba
[TGSI_NUM_CHANNELS
*c
] = lerp_2d(xw
, yw
,
1854 tx
[2][c
], tx
[3][c
]);
1859 img_filter_3d_linear(const struct sp_sampler_view
*sp_sview
,
1860 const struct sp_sampler
*sp_samp
,
1861 const struct img_filter_args
*args
,
1864 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
1865 const int width
= u_minify(texture
->width0
, args
->level
);
1866 const int height
= u_minify(texture
->height0
, args
->level
);
1867 const int depth
= u_minify(texture
->depth0
, args
->level
);
1868 int x0
, x1
, y0
, y1
, z0
, z1
;
1869 float xw
, yw
, zw
; /* interpolation weights */
1870 union tex_tile_address addr
;
1871 const float *tx00
, *tx01
, *tx02
, *tx03
, *tx10
, *tx11
, *tx12
, *tx13
;
1875 addr
.bits
.level
= args
->level
;
1881 sp_samp
->linear_texcoord_s(args
->s
, width
, args
->offset
[0], &x0
, &x1
, &xw
);
1882 sp_samp
->linear_texcoord_t(args
->t
, height
, args
->offset
[1], &y0
, &y1
, &yw
);
1883 sp_samp
->linear_texcoord_p(args
->p
, depth
, args
->offset
[2], &z0
, &z1
, &zw
);
1885 tx00
= get_texel_3d(sp_sview
, sp_samp
, addr
, x0
, y0
, z0
);
1886 tx01
= get_texel_3d(sp_sview
, sp_samp
, addr
, x1
, y0
, z0
);
1887 tx02
= get_texel_3d(sp_sview
, sp_samp
, addr
, x0
, y1
, z0
);
1888 tx03
= get_texel_3d(sp_sview
, sp_samp
, addr
, x1
, y1
, z0
);
1890 tx10
= get_texel_3d(sp_sview
, sp_samp
, addr
, x0
, y0
, z1
);
1891 tx11
= get_texel_3d(sp_sview
, sp_samp
, addr
, x1
, y0
, z1
);
1892 tx12
= get_texel_3d(sp_sview
, sp_samp
, addr
, x0
, y1
, z1
);
1893 tx13
= get_texel_3d(sp_sview
, sp_samp
, addr
, x1
, y1
, z1
);
1895 /* interpolate R, G, B, A */
1896 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
1897 rgba
[TGSI_NUM_CHANNELS
*c
] = lerp_3d(xw
, yw
, zw
,
1905 /* Calculate level of detail for every fragment,
1906 * with lambda already computed.
1907 * Note that lambda has already been biased by global LOD bias.
1908 * \param biased_lambda per-quad lambda.
1909 * \param lod_in per-fragment lod_bias or explicit_lod.
1910 * \param lod returns the per-fragment lod.
1913 compute_lod(const struct pipe_sampler_state
*sampler
,
1914 enum tgsi_sampler_control control
,
1915 const float biased_lambda
,
1916 const float lod_in
[TGSI_QUAD_SIZE
],
1917 float lod
[TGSI_QUAD_SIZE
])
1919 const float min_lod
= sampler
->min_lod
;
1920 const float max_lod
= sampler
->max_lod
;
1924 case TGSI_SAMPLER_LOD_NONE
:
1925 case TGSI_SAMPLER_LOD_ZERO
:
1926 lod
[0] = lod
[1] = lod
[2] = lod
[3] = CLAMP(biased_lambda
, min_lod
, max_lod
);
1928 case TGSI_SAMPLER_DERIVS_EXPLICIT
:
1929 for (i
= 0; i
< TGSI_QUAD_SIZE
; i
++)
1932 case TGSI_SAMPLER_LOD_BIAS
:
1933 for (i
= 0; i
< TGSI_QUAD_SIZE
; i
++) {
1934 lod
[i
] = biased_lambda
+ lod_in
[i
];
1935 lod
[i
] = CLAMP(lod
[i
], min_lod
, max_lod
);
1938 case TGSI_SAMPLER_LOD_EXPLICIT
:
1939 for (i
= 0; i
< TGSI_QUAD_SIZE
; i
++) {
1940 lod
[i
] = CLAMP(lod_in
[i
], min_lod
, max_lod
);
1945 lod
[0] = lod
[1] = lod
[2] = lod
[3] = 0.0f
;
1950 /* Calculate level of detail for every fragment. The computed value is not
1951 * clamped to lod_min and lod_max.
1952 * \param lod_in per-fragment lod_bias or explicit_lod.
1953 * \param lod results per-fragment lod.
1956 compute_lambda_lod_unclamped(const struct sp_sampler_view
*sp_sview
,
1957 const struct sp_sampler
*sp_samp
,
1958 const float s
[TGSI_QUAD_SIZE
],
1959 const float t
[TGSI_QUAD_SIZE
],
1960 const float p
[TGSI_QUAD_SIZE
],
1961 const float derivs
[3][2][TGSI_QUAD_SIZE
],
1962 const float lod_in
[TGSI_QUAD_SIZE
],
1963 enum tgsi_sampler_control control
,
1964 float lod
[TGSI_QUAD_SIZE
])
1966 const struct pipe_sampler_state
*sampler
= &sp_samp
->base
;
1967 const float lod_bias
= sampler
->lod_bias
;
1972 case TGSI_SAMPLER_LOD_NONE
:
1973 lambda
= sp_sview
->compute_lambda(sp_sview
, s
, t
, p
) + lod_bias
;
1974 lod
[0] = lod
[1] = lod
[2] = lod
[3] = lambda
;
1976 case TGSI_SAMPLER_DERIVS_EXPLICIT
:
1977 for (i
= 0; i
< TGSI_QUAD_SIZE
; i
++)
1978 lod
[i
] = sp_sview
->compute_lambda_from_grad(sp_sview
, derivs
, i
);
1980 case TGSI_SAMPLER_LOD_BIAS
:
1981 lambda
= sp_sview
->compute_lambda(sp_sview
, s
, t
, p
) + lod_bias
;
1982 for (i
= 0; i
< TGSI_QUAD_SIZE
; i
++) {
1983 lod
[i
] = lambda
+ lod_in
[i
];
1986 case TGSI_SAMPLER_LOD_EXPLICIT
:
1987 for (i
= 0; i
< TGSI_QUAD_SIZE
; i
++) {
1988 lod
[i
] = lod_in
[i
] + lod_bias
;
1991 case TGSI_SAMPLER_LOD_ZERO
:
1992 case TGSI_SAMPLER_GATHER
:
1993 lod
[0] = lod
[1] = lod
[2] = lod
[3] = lod_bias
;
1997 lod
[0] = lod
[1] = lod
[2] = lod
[3] = 0.0f
;
2001 /* Calculate level of detail for every fragment.
2002 * \param lod_in per-fragment lod_bias or explicit_lod.
2003 * \param lod results per-fragment lod.
2006 compute_lambda_lod(const struct sp_sampler_view
*sp_sview
,
2007 const struct sp_sampler
*sp_samp
,
2008 const float s
[TGSI_QUAD_SIZE
],
2009 const float t
[TGSI_QUAD_SIZE
],
2010 const float p
[TGSI_QUAD_SIZE
],
2011 float derivs
[3][2][TGSI_QUAD_SIZE
],
2012 const float lod_in
[TGSI_QUAD_SIZE
],
2013 enum tgsi_sampler_control control
,
2014 float lod
[TGSI_QUAD_SIZE
])
2016 const struct pipe_sampler_state
*sampler
= &sp_samp
->base
;
2017 const float min_lod
= sampler
->min_lod
;
2018 const float max_lod
= sampler
->max_lod
;
2021 compute_lambda_lod_unclamped(sp_sview
, sp_samp
,
2022 s
, t
, p
, derivs
, lod_in
, control
, lod
);
2023 for (i
= 0; i
< TGSI_QUAD_SIZE
; i
++) {
2024 lod
[i
] = CLAMP(lod
[i
], min_lod
, max_lod
);
2028 static inline unsigned
2029 get_gather_component(const float lod_in
[TGSI_QUAD_SIZE
])
2031 /* gather component is stored in lod_in slot as unsigned */
2032 return (*(unsigned int *)lod_in
) & 0x3;
2036 * Clamps given lod to both lod limits and mip level limits. Clamping to the
2037 * latter limits is done so that lod is relative to the first (base) level.
2040 clamp_lod(const struct sp_sampler_view
*sp_sview
,
2041 const struct sp_sampler
*sp_samp
,
2042 const float lod
[TGSI_QUAD_SIZE
],
2043 float clamped
[TGSI_QUAD_SIZE
])
2045 const float min_lod
= sp_samp
->base
.min_lod
;
2046 const float max_lod
= sp_samp
->base
.max_lod
;
2047 const float min_level
= sp_sview
->base
.u
.tex
.first_level
;
2048 const float max_level
= sp_sview
->base
.u
.tex
.last_level
;
2051 for (i
= 0; i
< TGSI_QUAD_SIZE
; i
++) {
2054 cl
= CLAMP(cl
, min_lod
, max_lod
);
2055 cl
= CLAMP(cl
, 0, max_level
- min_level
);
2061 * Get mip level relative to base level for linear mip filter
2064 mip_rel_level_linear(const struct sp_sampler_view
*sp_sview
,
2065 const struct sp_sampler
*sp_samp
,
2066 const float lod
[TGSI_QUAD_SIZE
],
2067 float level
[TGSI_QUAD_SIZE
])
2069 clamp_lod(sp_sview
, sp_samp
, lod
, level
);
2073 mip_filter_linear(const struct sp_sampler_view
*sp_sview
,
2074 const struct sp_sampler
*sp_samp
,
2075 img_filter_func min_filter
,
2076 img_filter_func mag_filter
,
2077 const float s
[TGSI_QUAD_SIZE
],
2078 const float t
[TGSI_QUAD_SIZE
],
2079 const float p
[TGSI_QUAD_SIZE
],
2081 const float lod
[TGSI_QUAD_SIZE
],
2082 const struct filter_args
*filt_args
,
2083 float rgba
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
])
2085 const struct pipe_sampler_view
*psview
= &sp_sview
->base
;
2087 struct img_filter_args args
;
2089 args
.offset
= filt_args
->offset
;
2090 args
.gather_only
= filt_args
->control
== TGSI_SAMPLER_GATHER
;
2091 args
.gather_comp
= gather_comp
;
2093 for (j
= 0; j
< TGSI_QUAD_SIZE
; j
++) {
2094 const int level0
= psview
->u
.tex
.first_level
+ (int)lod
[j
];
2099 args
.face_id
= filt_args
->faces
[j
];
2101 if (lod
[j
] <= 0.0 && !args
.gather_only
) {
2102 args
.level
= psview
->u
.tex
.first_level
;
2103 mag_filter(sp_sview
, sp_samp
, &args
, &rgba
[0][j
]);
2105 else if (level0
>= (int) psview
->u
.tex
.last_level
) {
2106 args
.level
= psview
->u
.tex
.last_level
;
2107 min_filter(sp_sview
, sp_samp
, &args
, &rgba
[0][j
]);
2110 float levelBlend
= frac(lod
[j
]);
2111 float rgbax
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
];
2114 args
.level
= level0
;
2115 min_filter(sp_sview
, sp_samp
, &args
, &rgbax
[0][0]);
2116 args
.level
= level0
+1;
2117 min_filter(sp_sview
, sp_samp
, &args
, &rgbax
[0][1]);
2119 for (c
= 0; c
< 4; c
++) {
2120 rgba
[c
][j
] = lerp(levelBlend
, rgbax
[c
][0], rgbax
[c
][1]);
2126 print_sample_4(__FUNCTION__
, rgba
);
2132 * Get mip level relative to base level for nearest mip filter
2135 mip_rel_level_nearest(const struct sp_sampler_view
*sp_sview
,
2136 const struct sp_sampler
*sp_samp
,
2137 const float lod
[TGSI_QUAD_SIZE
],
2138 float level
[TGSI_QUAD_SIZE
])
2142 clamp_lod(sp_sview
, sp_samp
, lod
, level
);
2143 for (j
= 0; j
< TGSI_QUAD_SIZE
; j
++)
2144 /* TODO: It should rather be:
2145 * level[j] = ceil(level[j] + 0.5F) - 1.0F;
2147 level
[j
] = (int)(level
[j
] + 0.5F
);
2151 * Compute nearest mipmap level from texcoords.
2152 * Then sample the texture level for four elements of a quad.
2153 * \param c0 the LOD bias factors, or absolute LODs (depending on control)
2156 mip_filter_nearest(const struct sp_sampler_view
*sp_sview
,
2157 const struct sp_sampler
*sp_samp
,
2158 img_filter_func min_filter
,
2159 img_filter_func mag_filter
,
2160 const float s
[TGSI_QUAD_SIZE
],
2161 const float t
[TGSI_QUAD_SIZE
],
2162 const float p
[TGSI_QUAD_SIZE
],
2163 int gather_component
,
2164 const float lod
[TGSI_QUAD_SIZE
],
2165 const struct filter_args
*filt_args
,
2166 float rgba
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
])
2168 const struct pipe_sampler_view
*psview
= &sp_sview
->base
;
2170 struct img_filter_args args
;
2172 args
.offset
= filt_args
->offset
;
2173 args
.gather_only
= filt_args
->control
== TGSI_SAMPLER_GATHER
;
2174 args
.gather_comp
= gather_component
;
2176 for (j
= 0; j
< TGSI_QUAD_SIZE
; j
++) {
2180 args
.face_id
= filt_args
->faces
[j
];
2182 if (lod
[j
] <= 0.0f
&& !args
.gather_only
) {
2183 args
.level
= psview
->u
.tex
.first_level
;
2184 mag_filter(sp_sview
, sp_samp
, &args
, &rgba
[0][j
]);
2186 const int level
= psview
->u
.tex
.first_level
+ (int)(lod
[j
] + 0.5F
);
2187 args
.level
= MIN2(level
, (int)psview
->u
.tex
.last_level
);
2188 min_filter(sp_sview
, sp_samp
, &args
, &rgba
[0][j
]);
2193 print_sample_4(__FUNCTION__
, rgba
);
2199 * Get mip level relative to base level for none mip filter
2202 mip_rel_level_none(const struct sp_sampler_view
*sp_sview
,
2203 const struct sp_sampler
*sp_samp
,
2204 const float lod
[TGSI_QUAD_SIZE
],
2205 float level
[TGSI_QUAD_SIZE
])
2209 for (j
= 0; j
< TGSI_QUAD_SIZE
; j
++) {
2215 mip_filter_none(const struct sp_sampler_view
*sp_sview
,
2216 const struct sp_sampler
*sp_samp
,
2217 img_filter_func min_filter
,
2218 img_filter_func mag_filter
,
2219 const float s
[TGSI_QUAD_SIZE
],
2220 const float t
[TGSI_QUAD_SIZE
],
2221 const float p
[TGSI_QUAD_SIZE
],
2222 int gather_component
,
2223 const float lod
[TGSI_QUAD_SIZE
],
2224 const struct filter_args
*filt_args
,
2225 float rgba
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
])
2228 struct img_filter_args args
;
2230 args
.level
= sp_sview
->base
.u
.tex
.first_level
;
2231 args
.offset
= filt_args
->offset
;
2232 args
.gather_only
= filt_args
->control
== TGSI_SAMPLER_GATHER
;
2233 args
.gather_comp
= gather_component
;
2235 for (j
= 0; j
< TGSI_QUAD_SIZE
; j
++) {
2239 args
.face_id
= filt_args
->faces
[j
];
2240 if (lod
[j
] <= 0.0f
&& !args
.gather_only
) {
2241 mag_filter(sp_sview
, sp_samp
, &args
, &rgba
[0][j
]);
2244 min_filter(sp_sview
, sp_samp
, &args
, &rgba
[0][j
]);
2251 * Get mip level relative to base level for none mip filter
2254 mip_rel_level_none_no_filter_select(const struct sp_sampler_view
*sp_sview
,
2255 const struct sp_sampler
*sp_samp
,
2256 const float lod
[TGSI_QUAD_SIZE
],
2257 float level
[TGSI_QUAD_SIZE
])
2259 mip_rel_level_none(sp_sview
, sp_samp
, lod
, level
);
2263 mip_filter_none_no_filter_select(const struct sp_sampler_view
*sp_sview
,
2264 const struct sp_sampler
*sp_samp
,
2265 img_filter_func min_filter
,
2266 img_filter_func mag_filter
,
2267 const float s
[TGSI_QUAD_SIZE
],
2268 const float t
[TGSI_QUAD_SIZE
],
2269 const float p
[TGSI_QUAD_SIZE
],
2271 const float lod_in
[TGSI_QUAD_SIZE
],
2272 const struct filter_args
*filt_args
,
2273 float rgba
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
])
2276 struct img_filter_args args
;
2277 args
.level
= sp_sview
->base
.u
.tex
.first_level
;
2278 args
.offset
= filt_args
->offset
;
2279 args
.gather_only
= filt_args
->control
== TGSI_SAMPLER_GATHER
;
2280 args
.gather_comp
= gather_comp
;
2281 for (j
= 0; j
< TGSI_QUAD_SIZE
; j
++) {
2285 args
.face_id
= filt_args
->faces
[j
];
2286 mag_filter(sp_sview
, sp_samp
, &args
, &rgba
[0][j
]);
2291 /* For anisotropic filtering */
2292 #define WEIGHT_LUT_SIZE 1024
2294 static const float *weightLut
= NULL
;
2297 * Creates the look-up table used to speed-up EWA sampling
2300 create_filter_table(void)
2304 float *lut
= (float *) MALLOC(WEIGHT_LUT_SIZE
* sizeof(float));
2306 for (i
= 0; i
< WEIGHT_LUT_SIZE
; ++i
) {
2307 const float alpha
= 2;
2308 const float r2
= (float) i
/ (float) (WEIGHT_LUT_SIZE
- 1);
2309 const float weight
= (float) exp(-alpha
* r2
);
2318 * Elliptical weighted average (EWA) filter for producing high quality
2319 * anisotropic filtered results.
2320 * Based on the Higher Quality Elliptical Weighted Average Filter
2321 * published by Paul S. Heckbert in his Master's Thesis
2322 * "Fundamentals of Texture Mapping and Image Warping" (1989)
2325 img_filter_2d_ewa(const struct sp_sampler_view
*sp_sview
,
2326 const struct sp_sampler
*sp_samp
,
2327 img_filter_func min_filter
,
2328 img_filter_func mag_filter
,
2329 const float s
[TGSI_QUAD_SIZE
],
2330 const float t
[TGSI_QUAD_SIZE
],
2331 const float p
[TGSI_QUAD_SIZE
],
2332 const uint faces
[TGSI_QUAD_SIZE
],
2333 const int8_t *offset
,
2335 const float dudx
, const float dvdx
,
2336 const float dudy
, const float dvdy
,
2337 float rgba
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
])
2339 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
2341 // ??? Won't the image filters blow up if level is negative?
2342 const unsigned level0
= level
> 0 ? level
: 0;
2343 const float scaling
= 1.0f
/ (1 << level0
);
2344 const int width
= u_minify(texture
->width0
, level0
);
2345 const int height
= u_minify(texture
->height0
, level0
);
2346 struct img_filter_args args
;
2347 const float ux
= dudx
* scaling
;
2348 const float vx
= dvdx
* scaling
;
2349 const float uy
= dudy
* scaling
;
2350 const float vy
= dvdy
* scaling
;
2352 /* compute ellipse coefficients to bound the region:
2353 * A*x*x + B*x*y + C*y*y = F.
2355 float A
= vx
*vx
+vy
*vy
+1;
2356 float B
= -2*(ux
*vx
+uy
*vy
);
2357 float C
= ux
*ux
+uy
*uy
+1;
2358 float F
= A
*C
-B
*B
/4.0f
;
2360 /* check if it is an ellipse */
2361 /* assert(F > 0.0); */
2363 /* Compute the ellipse's (u,v) bounding box in texture space */
2364 const float d
= -B
*B
+4.0f
*C
*A
;
2365 const float box_u
= 2.0f
/ d
* sqrtf(d
*C
*F
); /* box_u -> half of bbox with */
2366 const float box_v
= 2.0f
/ d
* sqrtf(A
*d
*F
); /* box_v -> half of bbox height */
2368 float rgba_temp
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
];
2369 float s_buffer
[TGSI_QUAD_SIZE
];
2370 float t_buffer
[TGSI_QUAD_SIZE
];
2371 float weight_buffer
[TGSI_QUAD_SIZE
];
2374 /* For each quad, the du and dx values are the same and so the ellipse is
2375 * also the same. Note that texel/image access can only be performed using
2376 * a quad, i.e. it is not possible to get the pixel value for a single
2377 * tex coord. In order to have a better performance, the access is buffered
2378 * using the s_buffer/t_buffer and weight_buffer. Only when the buffer is
2379 * full, then the pixel values are read from the image.
2381 const float ddq
= 2 * A
;
2383 /* Scale ellipse formula to directly index the Filter Lookup Table.
2384 * i.e. scale so that F = WEIGHT_LUT_SIZE-1
2386 const double formScale
= (double) (WEIGHT_LUT_SIZE
- 1) / F
;
2390 /* F *= formScale; */ /* no need to scale F as we don't use it below here */
2393 args
.offset
= offset
;
2395 for (j
= 0; j
< TGSI_QUAD_SIZE
; j
++) {
2396 /* Heckbert MS thesis, p. 59; scan over the bounding box of the ellipse
2397 * and incrementally update the value of Ax^2+Bxy*Cy^2; when this
2398 * value, q, is less than F, we're inside the ellipse
2400 const float tex_u
= -0.5F
+ s
[j
] * texture
->width0
* scaling
;
2401 const float tex_v
= -0.5F
+ t
[j
] * texture
->height0
* scaling
;
2403 const int u0
= (int) floorf(tex_u
- box_u
);
2404 const int u1
= (int) ceilf(tex_u
+ box_u
);
2405 const int v0
= (int) floorf(tex_v
- box_v
);
2406 const int v1
= (int) ceilf(tex_v
+ box_v
);
2407 const float U
= u0
- tex_u
;
2409 float num
[4] = {0.0F
, 0.0F
, 0.0F
, 0.0F
};
2410 unsigned buffer_next
= 0;
2413 args
.face_id
= faces
[j
];
2415 for (v
= v0
; v
<= v1
; ++v
) {
2416 const float V
= v
- tex_v
;
2417 float dq
= A
* (2 * U
+ 1) + B
* V
;
2418 float q
= (C
* V
+ B
* U
) * V
+ A
* U
* U
;
2421 for (u
= u0
; u
<= u1
; ++u
) {
2422 /* Note that the ellipse has been pre-scaled so F =
2423 * WEIGHT_LUT_SIZE - 1
2425 if (q
< WEIGHT_LUT_SIZE
) {
2426 /* as a LUT is used, q must never be negative;
2427 * should not happen, though
2429 const int qClamped
= q
>= 0.0F
? q
: 0;
2430 const float weight
= weightLut
[qClamped
];
2432 weight_buffer
[buffer_next
] = weight
;
2433 s_buffer
[buffer_next
] = u
/ ((float) width
);
2434 t_buffer
[buffer_next
] = v
/ ((float) height
);
2437 if (buffer_next
== TGSI_QUAD_SIZE
) {
2438 /* 4 texel coords are in the buffer -> read it now */
2440 /* it is assumed that samp->min_img_filter is set to
2441 * img_filter_2d_nearest or one of the
2442 * accelerated img_filter_2d_nearest_XXX functions.
2444 for (jj
= 0; jj
< buffer_next
; jj
++) {
2445 args
.s
= s_buffer
[jj
];
2446 args
.t
= t_buffer
[jj
];
2448 min_filter(sp_sview
, sp_samp
, &args
, &rgba_temp
[0][jj
]);
2449 num
[0] += weight_buffer
[jj
] * rgba_temp
[0][jj
];
2450 num
[1] += weight_buffer
[jj
] * rgba_temp
[1][jj
];
2451 num
[2] += weight_buffer
[jj
] * rgba_temp
[2][jj
];
2452 num
[3] += weight_buffer
[jj
] * rgba_temp
[3][jj
];
2465 /* if the tex coord buffer contains unread values, we will read
2468 if (buffer_next
> 0) {
2470 /* it is assumed that samp->min_img_filter is set to
2471 * img_filter_2d_nearest or one of the
2472 * accelerated img_filter_2d_nearest_XXX functions.
2474 for (jj
= 0; jj
< buffer_next
; jj
++) {
2475 args
.s
= s_buffer
[jj
];
2476 args
.t
= t_buffer
[jj
];
2478 min_filter(sp_sview
, sp_samp
, &args
, &rgba_temp
[0][jj
]);
2479 num
[0] += weight_buffer
[jj
] * rgba_temp
[0][jj
];
2480 num
[1] += weight_buffer
[jj
] * rgba_temp
[1][jj
];
2481 num
[2] += weight_buffer
[jj
] * rgba_temp
[2][jj
];
2482 num
[3] += weight_buffer
[jj
] * rgba_temp
[3][jj
];
2487 /* Reaching this place would mean that no pixels intersected
2488 * the ellipse. This should never happen because the filter
2489 * we use always intersects at least one pixel.
2496 /* not enough pixels in resampling, resort to direct interpolation */
2500 min_filter(sp_sview
, sp_samp
, &args
, &rgba_temp
[0][j
]);
2502 num
[0] = rgba_temp
[0][j
];
2503 num
[1] = rgba_temp
[1][j
];
2504 num
[2] = rgba_temp
[2][j
];
2505 num
[3] = rgba_temp
[3][j
];
2508 rgba
[0][j
] = num
[0] / den
;
2509 rgba
[1][j
] = num
[1] / den
;
2510 rgba
[2][j
] = num
[2] / den
;
2511 rgba
[3][j
] = num
[3] / den
;
2517 * Get mip level relative to base level for linear mip filter
2520 mip_rel_level_linear_aniso(const struct sp_sampler_view
*sp_sview
,
2521 const struct sp_sampler
*sp_samp
,
2522 const float lod
[TGSI_QUAD_SIZE
],
2523 float level
[TGSI_QUAD_SIZE
])
2525 mip_rel_level_linear(sp_sview
, sp_samp
, lod
, level
);
2529 * Sample 2D texture using an anisotropic filter.
2532 mip_filter_linear_aniso(const struct sp_sampler_view
*sp_sview
,
2533 const struct sp_sampler
*sp_samp
,
2534 img_filter_func min_filter
,
2535 img_filter_func mag_filter
,
2536 const float s
[TGSI_QUAD_SIZE
],
2537 const float t
[TGSI_QUAD_SIZE
],
2538 const float p
[TGSI_QUAD_SIZE
],
2539 UNUSED
int gather_comp
,
2540 const float lod_in
[TGSI_QUAD_SIZE
],
2541 const struct filter_args
*filt_args
,
2542 float rgba
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
])
2544 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
2545 const struct pipe_sampler_view
*psview
= &sp_sview
->base
;
2548 float lod
[TGSI_QUAD_SIZE
];
2550 const float s_to_u
= u_minify(texture
->width0
, psview
->u
.tex
.first_level
);
2551 const float t_to_v
= u_minify(texture
->height0
, psview
->u
.tex
.first_level
);
2552 const float dudx
= (s
[QUAD_BOTTOM_RIGHT
] - s
[QUAD_BOTTOM_LEFT
]) * s_to_u
;
2553 const float dudy
= (s
[QUAD_TOP_LEFT
] - s
[QUAD_BOTTOM_LEFT
]) * s_to_u
;
2554 const float dvdx
= (t
[QUAD_BOTTOM_RIGHT
] - t
[QUAD_BOTTOM_LEFT
]) * t_to_v
;
2555 const float dvdy
= (t
[QUAD_TOP_LEFT
] - t
[QUAD_BOTTOM_LEFT
]) * t_to_v
;
2556 struct img_filter_args args
;
2558 args
.offset
= filt_args
->offset
;
2560 if (filt_args
->control
== TGSI_SAMPLER_LOD_BIAS
||
2561 filt_args
->control
== TGSI_SAMPLER_LOD_NONE
||
2563 filt_args
->control
== TGSI_SAMPLER_DERIVS_EXPLICIT
) {
2564 /* note: instead of working with Px and Py, we will use the
2565 * squared length instead, to avoid sqrt.
2567 const float Px2
= dudx
* dudx
+ dvdx
* dvdx
;
2568 const float Py2
= dudy
* dudy
+ dvdy
* dvdy
;
2573 const float maxEccentricity
= sp_samp
->base
.max_anisotropy
* sp_samp
->base
.max_anisotropy
;
2584 /* if the eccentricity of the ellipse is too big, scale up the shorter
2585 * of the two vectors to limit the maximum amount of work per pixel
2588 if (e
> maxEccentricity
) {
2589 /* float s=e / maxEccentricity;
2593 Pmin2
= Pmax2
/ maxEccentricity
;
2596 /* note: we need to have Pmin=sqrt(Pmin2) here, but we can avoid
2597 * this since 0.5*log(x) = log(sqrt(x))
2599 lambda
= 0.5F
* util_fast_log2(Pmin2
) + sp_samp
->base
.lod_bias
;
2600 compute_lod(&sp_samp
->base
, filt_args
->control
, lambda
, lod_in
, lod
);
2603 assert(filt_args
->control
== TGSI_SAMPLER_LOD_EXPLICIT
||
2604 filt_args
->control
== TGSI_SAMPLER_LOD_ZERO
);
2605 compute_lod(&sp_samp
->base
, filt_args
->control
, sp_samp
->base
.lod_bias
, lod_in
, lod
);
2608 /* XXX: Take into account all lod values.
2611 level0
= psview
->u
.tex
.first_level
+ (int)lambda
;
2613 /* If the ellipse covers the whole image, we can
2614 * simply return the average of the whole image.
2616 if (level0
>= (int) psview
->u
.tex
.last_level
) {
2618 for (j
= 0; j
< TGSI_QUAD_SIZE
; j
++) {
2622 args
.level
= psview
->u
.tex
.last_level
;
2623 args
.face_id
= filt_args
->faces
[j
];
2625 * XXX: we overwrote any linear filter with nearest, so this
2626 * isn't right (albeit if last level is 1x1 and no border it
2627 * will work just the same).
2629 min_filter(sp_sview
, sp_samp
, &args
, &rgba
[0][j
]);
2633 /* don't bother interpolating between multiple LODs; it doesn't
2634 * seem to be worth the extra running time.
2636 img_filter_2d_ewa(sp_sview
, sp_samp
, min_filter
, mag_filter
,
2637 s
, t
, p
, filt_args
->faces
, filt_args
->offset
,
2638 level0
, dudx
, dvdx
, dudy
, dvdy
, rgba
);
2642 print_sample_4(__FUNCTION__
, rgba
);
2647 * Get mip level relative to base level for linear mip filter
2650 mip_rel_level_linear_2d_linear_repeat_POT(
2651 const struct sp_sampler_view
*sp_sview
,
2652 const struct sp_sampler
*sp_samp
,
2653 const float lod
[TGSI_QUAD_SIZE
],
2654 float level
[TGSI_QUAD_SIZE
])
2656 mip_rel_level_linear(sp_sview
, sp_samp
, lod
, level
);
2660 * Specialized version of mip_filter_linear with hard-wired calls to
2661 * 2d lambda calculation and 2d_linear_repeat_POT img filters.
2664 mip_filter_linear_2d_linear_repeat_POT(
2665 const struct sp_sampler_view
*sp_sview
,
2666 const struct sp_sampler
*sp_samp
,
2667 img_filter_func min_filter
,
2668 img_filter_func mag_filter
,
2669 const float s
[TGSI_QUAD_SIZE
],
2670 const float t
[TGSI_QUAD_SIZE
],
2671 const float p
[TGSI_QUAD_SIZE
],
2673 const float lod
[TGSI_QUAD_SIZE
],
2674 const struct filter_args
*filt_args
,
2675 float rgba
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
])
2677 const struct pipe_sampler_view
*psview
= &sp_sview
->base
;
2680 for (j
= 0; j
< TGSI_QUAD_SIZE
; j
++) {
2681 const int level0
= psview
->u
.tex
.first_level
+ (int)lod
[j
];
2682 struct img_filter_args args
;
2683 /* Catches both negative and large values of level0:
2688 args
.face_id
= filt_args
->faces
[j
];
2689 args
.offset
= filt_args
->offset
;
2690 args
.gather_only
= filt_args
->control
== TGSI_SAMPLER_GATHER
;
2691 args
.gather_comp
= gather_comp
;
2692 if ((unsigned)level0
>= psview
->u
.tex
.last_level
) {
2694 args
.level
= psview
->u
.tex
.first_level
;
2696 args
.level
= psview
->u
.tex
.last_level
;
2697 img_filter_2d_linear_repeat_POT(sp_sview
, sp_samp
, &args
,
2702 const float levelBlend
= frac(lod
[j
]);
2703 float rgbax
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
];
2706 args
.level
= level0
;
2707 img_filter_2d_linear_repeat_POT(sp_sview
, sp_samp
, &args
, &rgbax
[0][0]);
2708 args
.level
= level0
+1;
2709 img_filter_2d_linear_repeat_POT(sp_sview
, sp_samp
, &args
, &rgbax
[0][1]);
2711 for (c
= 0; c
< TGSI_NUM_CHANNELS
; c
++)
2712 rgba
[c
][j
] = lerp(levelBlend
, rgbax
[c
][0], rgbax
[c
][1]);
2717 print_sample_4(__FUNCTION__
, rgba
);
2721 static const struct sp_filter_funcs funcs_linear
= {
2722 mip_rel_level_linear
,
2726 static const struct sp_filter_funcs funcs_nearest
= {
2727 mip_rel_level_nearest
,
2731 static const struct sp_filter_funcs funcs_none
= {
2736 static const struct sp_filter_funcs funcs_none_no_filter_select
= {
2737 mip_rel_level_none_no_filter_select
,
2738 mip_filter_none_no_filter_select
2741 static const struct sp_filter_funcs funcs_linear_aniso
= {
2742 mip_rel_level_linear_aniso
,
2743 mip_filter_linear_aniso
2746 static const struct sp_filter_funcs funcs_linear_2d_linear_repeat_POT
= {
2747 mip_rel_level_linear_2d_linear_repeat_POT
,
2748 mip_filter_linear_2d_linear_repeat_POT
2752 * Do shadow/depth comparisons.
2755 sample_compare(const struct sp_sampler_view
*sp_sview
,
2756 const struct sp_sampler
*sp_samp
,
2757 const float c0
[TGSI_QUAD_SIZE
],
2758 enum tgsi_sampler_control control
,
2759 float rgba
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
])
2761 const struct pipe_sampler_state
*sampler
= &sp_samp
->base
;
2763 int k
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
];
2765 const struct util_format_description
*format_desc
=
2766 util_format_description(sp_sview
->base
.format
);
2767 /* not entirely sure we couldn't end up with non-valid swizzle here */
2768 const unsigned chan_type
=
2769 format_desc
->swizzle
[0] <= PIPE_SWIZZLE_W
?
2770 format_desc
->channel
[format_desc
->swizzle
[0]].type
:
2771 UTIL_FORMAT_TYPE_FLOAT
;
2772 const bool is_gather
= (control
== TGSI_SAMPLER_GATHER
);
2775 * Compare texcoord 'p' (aka R) against texture value 'rgba[0]'
2776 * for 2D Array texture we need to use the 'c0' (aka Q).
2777 * When we sampled the depth texture, the depth value was put into all
2778 * RGBA channels. We look at the red channel here.
2783 if (chan_type
!= UTIL_FORMAT_TYPE_FLOAT
) {
2785 * clamping is a result of conversion to texture format, hence
2786 * doesn't happen with floats. Technically also should do comparison
2787 * in texture format (quantization!).
2789 pc
[0] = CLAMP(c0
[0], 0.0F
, 1.0F
);
2790 pc
[1] = CLAMP(c0
[1], 0.0F
, 1.0F
);
2791 pc
[2] = CLAMP(c0
[2], 0.0F
, 1.0F
);
2792 pc
[3] = CLAMP(c0
[3], 0.0F
, 1.0F
);
2800 for (v
= 0; v
< (is_gather
? TGSI_NUM_CHANNELS
: 1); v
++) {
2801 /* compare four texcoords vs. four texture samples */
2802 switch (sampler
->compare_func
) {
2803 case PIPE_FUNC_LESS
:
2804 k
[v
][0] = pc
[0] < rgba
[v
][0];
2805 k
[v
][1] = pc
[1] < rgba
[v
][1];
2806 k
[v
][2] = pc
[2] < rgba
[v
][2];
2807 k
[v
][3] = pc
[3] < rgba
[v
][3];
2809 case PIPE_FUNC_LEQUAL
:
2810 k
[v
][0] = pc
[0] <= rgba
[v
][0];
2811 k
[v
][1] = pc
[1] <= rgba
[v
][1];
2812 k
[v
][2] = pc
[2] <= rgba
[v
][2];
2813 k
[v
][3] = pc
[3] <= rgba
[v
][3];
2815 case PIPE_FUNC_GREATER
:
2816 k
[v
][0] = pc
[0] > rgba
[v
][0];
2817 k
[v
][1] = pc
[1] > rgba
[v
][1];
2818 k
[v
][2] = pc
[2] > rgba
[v
][2];
2819 k
[v
][3] = pc
[3] > rgba
[v
][3];
2821 case PIPE_FUNC_GEQUAL
:
2822 k
[v
][0] = pc
[0] >= rgba
[v
][0];
2823 k
[v
][1] = pc
[1] >= rgba
[v
][1];
2824 k
[v
][2] = pc
[2] >= rgba
[v
][2];
2825 k
[v
][3] = pc
[3] >= rgba
[v
][3];
2827 case PIPE_FUNC_EQUAL
:
2828 k
[v
][0] = pc
[0] == rgba
[v
][0];
2829 k
[v
][1] = pc
[1] == rgba
[v
][1];
2830 k
[v
][2] = pc
[2] == rgba
[v
][2];
2831 k
[v
][3] = pc
[3] == rgba
[v
][3];
2833 case PIPE_FUNC_NOTEQUAL
:
2834 k
[v
][0] = pc
[0] != rgba
[v
][0];
2835 k
[v
][1] = pc
[1] != rgba
[v
][1];
2836 k
[v
][2] = pc
[2] != rgba
[v
][2];
2837 k
[v
][3] = pc
[3] != rgba
[v
][3];
2839 case PIPE_FUNC_ALWAYS
:
2840 k
[v
][0] = k
[v
][1] = k
[v
][2] = k
[v
][3] = 1;
2842 case PIPE_FUNC_NEVER
:
2843 k
[v
][0] = k
[v
][1] = k
[v
][2] = k
[v
][3] = 0;
2846 k
[v
][0] = k
[v
][1] = k
[v
][2] = k
[v
][3] = 0;
2853 for (j
= 0; j
< TGSI_QUAD_SIZE
; j
++) {
2854 for (v
= 0; v
< TGSI_NUM_CHANNELS
; v
++) {
2855 rgba
[v
][j
] = k
[v
][j
];
2859 for (j
= 0; j
< TGSI_QUAD_SIZE
; j
++) {
2860 rgba
[0][j
] = k
[0][j
];
2861 rgba
[1][j
] = k
[0][j
];
2862 rgba
[2][j
] = k
[0][j
];
2869 do_swizzling(const struct pipe_sampler_view
*sview
,
2870 float in
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
],
2871 float out
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
])
2874 const unsigned swizzle_r
= sview
->swizzle_r
;
2875 const unsigned swizzle_g
= sview
->swizzle_g
;
2876 const unsigned swizzle_b
= sview
->swizzle_b
;
2877 const unsigned swizzle_a
= sview
->swizzle_a
;
2878 float oneval
= util_format_is_pure_integer(sview
->format
) ? uif(1) : 1.0f
;
2880 switch (swizzle_r
) {
2881 case PIPE_SWIZZLE_0
:
2882 for (j
= 0; j
< 4; j
++)
2885 case PIPE_SWIZZLE_1
:
2886 for (j
= 0; j
< 4; j
++)
2890 assert(swizzle_r
< 4);
2891 for (j
= 0; j
< 4; j
++)
2892 out
[0][j
] = in
[swizzle_r
][j
];
2895 switch (swizzle_g
) {
2896 case PIPE_SWIZZLE_0
:
2897 for (j
= 0; j
< 4; j
++)
2900 case PIPE_SWIZZLE_1
:
2901 for (j
= 0; j
< 4; j
++)
2905 assert(swizzle_g
< 4);
2906 for (j
= 0; j
< 4; j
++)
2907 out
[1][j
] = in
[swizzle_g
][j
];
2910 switch (swizzle_b
) {
2911 case PIPE_SWIZZLE_0
:
2912 for (j
= 0; j
< 4; j
++)
2915 case PIPE_SWIZZLE_1
:
2916 for (j
= 0; j
< 4; j
++)
2920 assert(swizzle_b
< 4);
2921 for (j
= 0; j
< 4; j
++)
2922 out
[2][j
] = in
[swizzle_b
][j
];
2925 switch (swizzle_a
) {
2926 case PIPE_SWIZZLE_0
:
2927 for (j
= 0; j
< 4; j
++)
2930 case PIPE_SWIZZLE_1
:
2931 for (j
= 0; j
< 4; j
++)
2935 assert(swizzle_a
< 4);
2936 for (j
= 0; j
< 4; j
++)
2937 out
[3][j
] = in
[swizzle_a
][j
];
2942 static wrap_nearest_func
2943 get_nearest_unorm_wrap(unsigned mode
)
2946 case PIPE_TEX_WRAP_CLAMP
:
2947 return wrap_nearest_unorm_clamp
;
2948 case PIPE_TEX_WRAP_CLAMP_TO_EDGE
:
2949 return wrap_nearest_unorm_clamp_to_edge
;
2950 case PIPE_TEX_WRAP_CLAMP_TO_BORDER
:
2951 return wrap_nearest_unorm_clamp_to_border
;
2953 debug_printf("illegal wrap mode %d with non-normalized coords\n", mode
);
2954 return wrap_nearest_unorm_clamp
;
2959 static wrap_nearest_func
2960 get_nearest_wrap(unsigned mode
)
2963 case PIPE_TEX_WRAP_REPEAT
:
2964 return wrap_nearest_repeat
;
2965 case PIPE_TEX_WRAP_CLAMP
:
2966 return wrap_nearest_clamp
;
2967 case PIPE_TEX_WRAP_CLAMP_TO_EDGE
:
2968 return wrap_nearest_clamp_to_edge
;
2969 case PIPE_TEX_WRAP_CLAMP_TO_BORDER
:
2970 return wrap_nearest_clamp_to_border
;
2971 case PIPE_TEX_WRAP_MIRROR_REPEAT
:
2972 return wrap_nearest_mirror_repeat
;
2973 case PIPE_TEX_WRAP_MIRROR_CLAMP
:
2974 return wrap_nearest_mirror_clamp
;
2975 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE
:
2976 return wrap_nearest_mirror_clamp_to_edge
;
2977 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER
:
2978 return wrap_nearest_mirror_clamp_to_border
;
2981 return wrap_nearest_repeat
;
2986 static wrap_linear_func
2987 get_linear_unorm_wrap(unsigned mode
)
2990 case PIPE_TEX_WRAP_CLAMP
:
2991 return wrap_linear_unorm_clamp
;
2992 case PIPE_TEX_WRAP_CLAMP_TO_EDGE
:
2993 return wrap_linear_unorm_clamp_to_edge
;
2994 case PIPE_TEX_WRAP_CLAMP_TO_BORDER
:
2995 return wrap_linear_unorm_clamp_to_border
;
2997 debug_printf("illegal wrap mode %d with non-normalized coords\n", mode
);
2998 return wrap_linear_unorm_clamp
;
3003 static wrap_linear_func
3004 get_linear_wrap(unsigned mode
)
3007 case PIPE_TEX_WRAP_REPEAT
:
3008 return wrap_linear_repeat
;
3009 case PIPE_TEX_WRAP_CLAMP
:
3010 return wrap_linear_clamp
;
3011 case PIPE_TEX_WRAP_CLAMP_TO_EDGE
:
3012 return wrap_linear_clamp_to_edge
;
3013 case PIPE_TEX_WRAP_CLAMP_TO_BORDER
:
3014 return wrap_linear_clamp_to_border
;
3015 case PIPE_TEX_WRAP_MIRROR_REPEAT
:
3016 return wrap_linear_mirror_repeat
;
3017 case PIPE_TEX_WRAP_MIRROR_CLAMP
:
3018 return wrap_linear_mirror_clamp
;
3019 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE
:
3020 return wrap_linear_mirror_clamp_to_edge
;
3021 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER
:
3022 return wrap_linear_mirror_clamp_to_border
;
3025 return wrap_linear_repeat
;
3031 * Is swizzling needed for the given state key?
3034 any_swizzle(const struct pipe_sampler_view
*view
)
3036 return (view
->swizzle_r
!= PIPE_SWIZZLE_X
||
3037 view
->swizzle_g
!= PIPE_SWIZZLE_Y
||
3038 view
->swizzle_b
!= PIPE_SWIZZLE_Z
||
3039 view
->swizzle_a
!= PIPE_SWIZZLE_W
);
3043 static img_filter_func
3044 get_img_filter(const struct sp_sampler_view
*sp_sview
,
3045 const struct pipe_sampler_state
*sampler
,
3046 unsigned filter
, bool gather
)
3048 switch (sp_sview
->base
.target
) {
3050 case PIPE_TEXTURE_1D
:
3051 if (filter
== PIPE_TEX_FILTER_NEAREST
)
3052 return img_filter_1d_nearest
;
3054 return img_filter_1d_linear
;
3056 case PIPE_TEXTURE_1D_ARRAY
:
3057 if (filter
== PIPE_TEX_FILTER_NEAREST
)
3058 return img_filter_1d_array_nearest
;
3060 return img_filter_1d_array_linear
;
3062 case PIPE_TEXTURE_2D
:
3063 case PIPE_TEXTURE_RECT
:
3064 /* Try for fast path:
3066 if (!gather
&& sp_sview
->pot2d
&&
3067 sampler
->wrap_s
== sampler
->wrap_t
&&
3068 sampler
->normalized_coords
)
3070 switch (sampler
->wrap_s
) {
3071 case PIPE_TEX_WRAP_REPEAT
:
3073 case PIPE_TEX_FILTER_NEAREST
:
3074 return img_filter_2d_nearest_repeat_POT
;
3075 case PIPE_TEX_FILTER_LINEAR
:
3076 return img_filter_2d_linear_repeat_POT
;
3081 case PIPE_TEX_WRAP_CLAMP
:
3083 case PIPE_TEX_FILTER_NEAREST
:
3084 return img_filter_2d_nearest_clamp_POT
;
3090 /* Otherwise use default versions:
3092 if (filter
== PIPE_TEX_FILTER_NEAREST
)
3093 return img_filter_2d_nearest
;
3095 return img_filter_2d_linear
;
3097 case PIPE_TEXTURE_2D_ARRAY
:
3098 if (filter
== PIPE_TEX_FILTER_NEAREST
)
3099 return img_filter_2d_array_nearest
;
3101 return img_filter_2d_array_linear
;
3103 case PIPE_TEXTURE_CUBE
:
3104 if (filter
== PIPE_TEX_FILTER_NEAREST
)
3105 return img_filter_cube_nearest
;
3107 return img_filter_cube_linear
;
3109 case PIPE_TEXTURE_CUBE_ARRAY
:
3110 if (filter
== PIPE_TEX_FILTER_NEAREST
)
3111 return img_filter_cube_array_nearest
;
3113 return img_filter_cube_array_linear
;
3115 case PIPE_TEXTURE_3D
:
3116 if (filter
== PIPE_TEX_FILTER_NEAREST
)
3117 return img_filter_3d_nearest
;
3119 return img_filter_3d_linear
;
3123 return img_filter_1d_nearest
;
3128 * Get mip filter funcs, and optionally both img min filter and img mag
3129 * filter. Note that both img filter function pointers must be either non-NULL
3133 get_filters(const struct sp_sampler_view
*sp_sview
,
3134 const struct sp_sampler
*sp_samp
,
3135 const enum tgsi_sampler_control control
,
3136 const struct sp_filter_funcs
**funcs
,
3137 img_filter_func
*min
,
3138 img_filter_func
*mag
)
3141 if (control
== TGSI_SAMPLER_GATHER
) {
3142 *funcs
= &funcs_nearest
;
3144 *min
= get_img_filter(sp_sview
, &sp_samp
->base
,
3145 PIPE_TEX_FILTER_LINEAR
, true);
3147 } else if (sp_sview
->pot2d
& sp_samp
->min_mag_equal_repeat_linear
) {
3148 *funcs
= &funcs_linear_2d_linear_repeat_POT
;
3150 *funcs
= sp_samp
->filter_funcs
;
3153 *min
= get_img_filter(sp_sview
, &sp_samp
->base
,
3154 sp_samp
->min_img_filter
, false);
3155 if (sp_samp
->min_mag_equal
) {
3158 *mag
= get_img_filter(sp_sview
, &sp_samp
->base
,
3159 sp_samp
->base
.mag_img_filter
, false);
3166 sample_mip(const struct sp_sampler_view
*sp_sview
,
3167 const struct sp_sampler
*sp_samp
,
3168 const float s
[TGSI_QUAD_SIZE
],
3169 const float t
[TGSI_QUAD_SIZE
],
3170 const float p
[TGSI_QUAD_SIZE
],
3171 const float c0
[TGSI_QUAD_SIZE
],
3173 const float lod
[TGSI_QUAD_SIZE
],
3174 const struct filter_args
*filt_args
,
3175 float rgba
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
])
3177 const struct sp_filter_funcs
*funcs
= NULL
;
3178 img_filter_func min_img_filter
= NULL
;
3179 img_filter_func mag_img_filter
= NULL
;
3181 get_filters(sp_sview
, sp_samp
, filt_args
->control
,
3182 &funcs
, &min_img_filter
, &mag_img_filter
);
3184 funcs
->filter(sp_sview
, sp_samp
, min_img_filter
, mag_img_filter
,
3185 s
, t
, p
, gather_comp
, lod
, filt_args
, rgba
);
3187 if (sp_samp
->base
.compare_mode
!= PIPE_TEX_COMPARE_NONE
) {
3188 sample_compare(sp_sview
, sp_samp
, c0
, filt_args
->control
, rgba
);
3191 if (sp_sview
->need_swizzle
&& filt_args
->control
!= TGSI_SAMPLER_GATHER
) {
3192 float rgba_temp
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
];
3193 memcpy(rgba_temp
, rgba
, sizeof(rgba_temp
));
3194 do_swizzling(&sp_sview
->base
, rgba_temp
, rgba
);
3201 * This function uses cube texture coordinates to choose a face of a cube and
3202 * computes the 2D cube face coordinates. Puts face info into the sampler
3206 convert_cube(const struct sp_sampler_view
*sp_sview
,
3207 const struct sp_sampler
*sp_samp
,
3208 const float s
[TGSI_QUAD_SIZE
],
3209 const float t
[TGSI_QUAD_SIZE
],
3210 const float p
[TGSI_QUAD_SIZE
],
3211 const float c0
[TGSI_QUAD_SIZE
],
3212 float ssss
[TGSI_QUAD_SIZE
],
3213 float tttt
[TGSI_QUAD_SIZE
],
3214 float pppp
[TGSI_QUAD_SIZE
],
3215 uint faces
[TGSI_QUAD_SIZE
])
3225 direction target sc tc ma
3226 ---------- ------------------------------- --- --- ---
3227 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
3228 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
3229 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
3230 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
3231 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
3232 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
3235 /* Choose the cube face and compute new s/t coords for the 2D face.
3237 * Use the same cube face for all four pixels in the quad.
3239 * This isn't ideal, but if we want to use a different cube face
3240 * per pixel in the quad, we'd have to also compute the per-face
3241 * LOD here too. That's because the four post-face-selection
3242 * texcoords are no longer related to each other (they're
3243 * per-face!) so we can't use subtraction to compute the partial
3244 * deriviates to compute the LOD. Doing so (near cube edges
3245 * anyway) gives us pretty much random values.
3247 for (j
= 0; j
< TGSI_QUAD_SIZE
; j
++) {
3248 const float rx
= s
[j
], ry
= t
[j
], rz
= p
[j
];
3249 const float arx
= fabsf(rx
), ary
= fabsf(ry
), arz
= fabsf(rz
);
3251 if (arx
>= ary
&& arx
>= arz
) {
3252 const float sign
= (rx
>= 0.0F
) ? 1.0F
: -1.0F
;
3253 const uint face
= (rx
>= 0.0F
) ?
3254 PIPE_TEX_FACE_POS_X
: PIPE_TEX_FACE_NEG_X
;
3255 const float ima
= -0.5F
/ fabsf(s
[j
]);
3256 ssss
[j
] = sign
* p
[j
] * ima
+ 0.5F
;
3257 tttt
[j
] = t
[j
] * ima
+ 0.5F
;
3260 else if (ary
>= arx
&& ary
>= arz
) {
3261 const float sign
= (ry
>= 0.0F
) ? 1.0F
: -1.0F
;
3262 const uint face
= (ry
>= 0.0F
) ?
3263 PIPE_TEX_FACE_POS_Y
: PIPE_TEX_FACE_NEG_Y
;
3264 const float ima
= -0.5F
/ fabsf(t
[j
]);
3265 ssss
[j
] = -s
[j
] * ima
+ 0.5F
;
3266 tttt
[j
] = sign
* -p
[j
] * ima
+ 0.5F
;
3270 const float sign
= (rz
>= 0.0F
) ? 1.0F
: -1.0F
;
3271 const uint face
= (rz
>= 0.0F
) ?
3272 PIPE_TEX_FACE_POS_Z
: PIPE_TEX_FACE_NEG_Z
;
3273 const float ima
= -0.5F
/ fabsf(p
[j
]);
3274 ssss
[j
] = sign
* -s
[j
] * ima
+ 0.5F
;
3275 tttt
[j
] = t
[j
] * ima
+ 0.5F
;
3283 sp_get_dims(const struct sp_sampler_view
*sp_sview
,
3287 const struct pipe_sampler_view
*view
= &sp_sview
->base
;
3288 const struct pipe_resource
*texture
= view
->texture
;
3290 if (view
->target
== PIPE_BUFFER
) {
3291 dims
[0] = view
->u
.buf
.size
/ util_format_get_blocksize(view
->format
);
3292 /* the other values are undefined, but let's avoid potential valgrind
3295 dims
[1] = dims
[2] = dims
[3] = 0;
3299 /* undefined according to EXT_gpu_program */
3300 level
+= view
->u
.tex
.first_level
;
3301 if (level
> view
->u
.tex
.last_level
)
3304 dims
[3] = view
->u
.tex
.last_level
- view
->u
.tex
.first_level
+ 1;
3305 dims
[0] = u_minify(texture
->width0
, level
);
3307 switch (view
->target
) {
3308 case PIPE_TEXTURE_1D_ARRAY
:
3309 dims
[1] = view
->u
.tex
.last_layer
- view
->u
.tex
.first_layer
+ 1;
3311 case PIPE_TEXTURE_1D
:
3313 case PIPE_TEXTURE_2D_ARRAY
:
3314 dims
[2] = view
->u
.tex
.last_layer
- view
->u
.tex
.first_layer
+ 1;
3316 case PIPE_TEXTURE_2D
:
3317 case PIPE_TEXTURE_CUBE
:
3318 case PIPE_TEXTURE_RECT
:
3319 dims
[1] = u_minify(texture
->height0
, level
);
3321 case PIPE_TEXTURE_3D
:
3322 dims
[1] = u_minify(texture
->height0
, level
);
3323 dims
[2] = u_minify(texture
->depth0
, level
);
3325 case PIPE_TEXTURE_CUBE_ARRAY
:
3326 dims
[1] = u_minify(texture
->height0
, level
);
3327 dims
[2] = (view
->u
.tex
.last_layer
- view
->u
.tex
.first_layer
+ 1) / 6;
3330 assert(!"unexpected texture target in sp_get_dims()");
3336 * This function is only used for getting unfiltered texels via the
3337 * TXF opcode. The GL spec says that out-of-bounds texel fetches
3338 * produce undefined results. Instead of crashing, lets just clamp
3339 * coords to the texture image size.
3342 sp_get_texels(const struct sp_sampler_view
*sp_sview
,
3343 const int v_i
[TGSI_QUAD_SIZE
],
3344 const int v_j
[TGSI_QUAD_SIZE
],
3345 const int v_k
[TGSI_QUAD_SIZE
],
3346 const int lod
[TGSI_QUAD_SIZE
],
3347 const int8_t offset
[3],
3348 float rgba
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
])
3350 union tex_tile_address addr
;
3351 const struct pipe_resource
*texture
= sp_sview
->base
.texture
;
3354 /* TODO write a better test for LOD */
3355 const unsigned level
=
3356 sp_sview
->base
.target
== PIPE_BUFFER
? 0 :
3357 CLAMP(lod
[0] + sp_sview
->base
.u
.tex
.first_level
,
3358 sp_sview
->base
.u
.tex
.first_level
,
3359 sp_sview
->base
.u
.tex
.last_level
);
3360 const int width
= u_minify(texture
->width0
, level
);
3361 const int height
= u_minify(texture
->height0
, level
);
3362 const int depth
= u_minify(texture
->depth0
, level
);
3363 unsigned elem_size
, first_element
, last_element
;
3366 addr
.bits
.level
= level
;
3368 switch (sp_sview
->base
.target
) {
3370 elem_size
= util_format_get_blocksize(sp_sview
->base
.format
);
3371 first_element
= sp_sview
->base
.u
.buf
.offset
/ elem_size
;
3372 last_element
= (sp_sview
->base
.u
.buf
.offset
+
3373 sp_sview
->base
.u
.buf
.size
) / elem_size
- 1;
3374 for (j
= 0; j
< TGSI_QUAD_SIZE
; j
++) {
3375 const int x
= CLAMP(v_i
[j
] + offset
[0] +
3379 tx
= get_texel_buffer_no_border(sp_sview
, addr
, x
, elem_size
);
3380 for (c
= 0; c
< 4; c
++) {
3385 case PIPE_TEXTURE_1D
:
3386 for (j
= 0; j
< TGSI_QUAD_SIZE
; j
++) {
3387 const int x
= CLAMP(v_i
[j
] + offset
[0], 0, width
- 1);
3388 tx
= get_texel_2d_no_border(sp_sview
, addr
, x
,
3389 sp_sview
->base
.u
.tex
.first_layer
);
3390 for (c
= 0; c
< 4; c
++) {
3395 case PIPE_TEXTURE_1D_ARRAY
:
3396 for (j
= 0; j
< TGSI_QUAD_SIZE
; j
++) {
3397 const int x
= CLAMP(v_i
[j
] + offset
[0], 0, width
- 1);
3398 const int y
= CLAMP(v_j
[j
], sp_sview
->base
.u
.tex
.first_layer
,
3399 sp_sview
->base
.u
.tex
.last_layer
);
3400 tx
= get_texel_2d_no_border(sp_sview
, addr
, x
, y
);
3401 for (c
= 0; c
< 4; c
++) {
3406 case PIPE_TEXTURE_2D
:
3407 case PIPE_TEXTURE_RECT
:
3408 for (j
= 0; j
< TGSI_QUAD_SIZE
; j
++) {
3409 const int x
= CLAMP(v_i
[j
] + offset
[0], 0, width
- 1);
3410 const int y
= CLAMP(v_j
[j
] + offset
[1], 0, height
- 1);
3411 tx
= get_texel_3d_no_border(sp_sview
, addr
, x
, y
,
3412 sp_sview
->base
.u
.tex
.first_layer
);
3413 for (c
= 0; c
< 4; c
++) {
3418 case PIPE_TEXTURE_2D_ARRAY
:
3419 for (j
= 0; j
< TGSI_QUAD_SIZE
; j
++) {
3420 const int x
= CLAMP(v_i
[j
] + offset
[0], 0, width
- 1);
3421 const int y
= CLAMP(v_j
[j
] + offset
[1], 0, height
- 1);
3422 const int layer
= CLAMP(v_k
[j
], sp_sview
->base
.u
.tex
.first_layer
,
3423 sp_sview
->base
.u
.tex
.last_layer
);
3424 tx
= get_texel_3d_no_border(sp_sview
, addr
, x
, y
, layer
);
3425 for (c
= 0; c
< 4; c
++) {
3430 case PIPE_TEXTURE_3D
:
3431 for (j
= 0; j
< TGSI_QUAD_SIZE
; j
++) {
3432 int x
= CLAMP(v_i
[j
] + offset
[0], 0, width
- 1);
3433 int y
= CLAMP(v_j
[j
] + offset
[1], 0, height
- 1);
3434 int z
= CLAMP(v_k
[j
] + offset
[2], 0, depth
- 1);
3435 tx
= get_texel_3d_no_border(sp_sview
, addr
, x
, y
, z
);
3436 for (c
= 0; c
< 4; c
++) {
3441 case PIPE_TEXTURE_CUBE
: /* TXF can't work on CUBE according to spec */
3442 case PIPE_TEXTURE_CUBE_ARRAY
:
3444 assert(!"Unknown or CUBE texture type in TXF processing\n");
3448 if (sp_sview
->need_swizzle
) {
3449 float rgba_temp
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
];
3450 memcpy(rgba_temp
, rgba
, sizeof(rgba_temp
));
3451 do_swizzling(&sp_sview
->base
, rgba_temp
, rgba
);
3457 softpipe_create_sampler_state(struct pipe_context
*pipe
,
3458 const struct pipe_sampler_state
*sampler
)
3460 struct sp_sampler
*samp
= CALLOC_STRUCT(sp_sampler
);
3462 samp
->base
= *sampler
;
3464 /* Note that (for instance) linear_texcoord_s and
3465 * nearest_texcoord_s may be active at the same time, if the
3466 * sampler min_img_filter differs from its mag_img_filter.
3468 if (sampler
->normalized_coords
) {
3469 samp
->linear_texcoord_s
= get_linear_wrap( sampler
->wrap_s
);
3470 samp
->linear_texcoord_t
= get_linear_wrap( sampler
->wrap_t
);
3471 samp
->linear_texcoord_p
= get_linear_wrap( sampler
->wrap_r
);
3473 samp
->nearest_texcoord_s
= get_nearest_wrap( sampler
->wrap_s
);
3474 samp
->nearest_texcoord_t
= get_nearest_wrap( sampler
->wrap_t
);
3475 samp
->nearest_texcoord_p
= get_nearest_wrap( sampler
->wrap_r
);
3478 samp
->linear_texcoord_s
= get_linear_unorm_wrap( sampler
->wrap_s
);
3479 samp
->linear_texcoord_t
= get_linear_unorm_wrap( sampler
->wrap_t
);
3480 samp
->linear_texcoord_p
= get_linear_unorm_wrap( sampler
->wrap_r
);
3482 samp
->nearest_texcoord_s
= get_nearest_unorm_wrap( sampler
->wrap_s
);
3483 samp
->nearest_texcoord_t
= get_nearest_unorm_wrap( sampler
->wrap_t
);
3484 samp
->nearest_texcoord_p
= get_nearest_unorm_wrap( sampler
->wrap_r
);
3487 samp
->min_img_filter
= sampler
->min_img_filter
;
3489 switch (sampler
->min_mip_filter
) {
3490 case PIPE_TEX_MIPFILTER_NONE
:
3491 if (sampler
->min_img_filter
== sampler
->mag_img_filter
)
3492 samp
->filter_funcs
= &funcs_none_no_filter_select
;
3494 samp
->filter_funcs
= &funcs_none
;
3497 case PIPE_TEX_MIPFILTER_NEAREST
:
3498 samp
->filter_funcs
= &funcs_nearest
;
3501 case PIPE_TEX_MIPFILTER_LINEAR
:
3502 if (sampler
->min_img_filter
== sampler
->mag_img_filter
&&
3503 sampler
->normalized_coords
&&
3504 sampler
->wrap_s
== PIPE_TEX_WRAP_REPEAT
&&
3505 sampler
->wrap_t
== PIPE_TEX_WRAP_REPEAT
&&
3506 sampler
->min_img_filter
== PIPE_TEX_FILTER_LINEAR
&&
3507 sampler
->max_anisotropy
<= 1) {
3508 samp
->min_mag_equal_repeat_linear
= TRUE
;
3510 samp
->filter_funcs
= &funcs_linear
;
3512 /* Anisotropic filtering extension. */
3513 if (sampler
->max_anisotropy
> 1) {
3514 samp
->filter_funcs
= &funcs_linear_aniso
;
3516 /* Override min_img_filter:
3517 * min_img_filter needs to be set to NEAREST since we need to access
3518 * each texture pixel as it is and weight it later; using linear
3519 * filters will have incorrect results.
3520 * By setting the filter to NEAREST here, we can avoid calling the
3521 * generic img_filter_2d_nearest in the anisotropic filter function,
3522 * making it possible to use one of the accelerated implementations
3524 samp
->min_img_filter
= PIPE_TEX_FILTER_NEAREST
;
3526 /* on first access create the lookup table containing the filter weights. */
3528 create_filter_table();
3533 if (samp
->min_img_filter
== sampler
->mag_img_filter
) {
3534 samp
->min_mag_equal
= TRUE
;
3537 return (void *)samp
;
3542 softpipe_get_lambda_func(const struct pipe_sampler_view
*view
,
3543 enum pipe_shader_type shader
)
3545 if (shader
!= PIPE_SHADER_FRAGMENT
)
3546 return compute_lambda_vert
;
3548 switch (view
->target
) {
3550 case PIPE_TEXTURE_1D
:
3551 case PIPE_TEXTURE_1D_ARRAY
:
3552 return compute_lambda_1d
;
3553 case PIPE_TEXTURE_2D
:
3554 case PIPE_TEXTURE_2D_ARRAY
:
3555 case PIPE_TEXTURE_RECT
:
3556 return compute_lambda_2d
;
3557 case PIPE_TEXTURE_CUBE
:
3558 case PIPE_TEXTURE_CUBE_ARRAY
:
3559 return compute_lambda_cube
;
3560 case PIPE_TEXTURE_3D
:
3561 return compute_lambda_3d
;
3564 return compute_lambda_1d
;
3569 struct pipe_sampler_view
*
3570 softpipe_create_sampler_view(struct pipe_context
*pipe
,
3571 struct pipe_resource
*resource
,
3572 const struct pipe_sampler_view
*templ
)
3574 struct sp_sampler_view
*sview
= CALLOC_STRUCT(sp_sampler_view
);
3575 const struct softpipe_resource
*spr
= (struct softpipe_resource
*)resource
;
3578 struct pipe_sampler_view
*view
= &sview
->base
;
3580 view
->reference
.count
= 1;
3581 view
->texture
= NULL
;
3582 pipe_resource_reference(&view
->texture
, resource
);
3583 view
->context
= pipe
;
3587 * This is possibly too lenient, but the primary reason is just
3588 * to catch state trackers which forget to initialize this, so
3589 * it only catches clearly impossible view targets.
3591 if (view
->target
!= resource
->target
) {
3592 if (view
->target
== PIPE_TEXTURE_1D
)
3593 assert(resource
->target
== PIPE_TEXTURE_1D_ARRAY
);
3594 else if (view
->target
== PIPE_TEXTURE_1D_ARRAY
)
3595 assert(resource
->target
== PIPE_TEXTURE_1D
);
3596 else if (view
->target
== PIPE_TEXTURE_2D
)
3597 assert(resource
->target
== PIPE_TEXTURE_2D_ARRAY
||
3598 resource
->target
== PIPE_TEXTURE_CUBE
||
3599 resource
->target
== PIPE_TEXTURE_CUBE_ARRAY
);
3600 else if (view
->target
== PIPE_TEXTURE_2D_ARRAY
)
3601 assert(resource
->target
== PIPE_TEXTURE_2D
||
3602 resource
->target
== PIPE_TEXTURE_CUBE
||
3603 resource
->target
== PIPE_TEXTURE_CUBE_ARRAY
);
3604 else if (view
->target
== PIPE_TEXTURE_CUBE
)
3605 assert(resource
->target
== PIPE_TEXTURE_CUBE_ARRAY
||
3606 resource
->target
== PIPE_TEXTURE_2D_ARRAY
);
3607 else if (view
->target
== PIPE_TEXTURE_CUBE_ARRAY
)
3608 assert(resource
->target
== PIPE_TEXTURE_CUBE
||
3609 resource
->target
== PIPE_TEXTURE_2D_ARRAY
);
3615 if (any_swizzle(view
)) {
3616 sview
->need_swizzle
= TRUE
;
3619 sview
->need_cube_convert
= (view
->target
== PIPE_TEXTURE_CUBE
||
3620 view
->target
== PIPE_TEXTURE_CUBE_ARRAY
);
3621 sview
->pot2d
= spr
->pot
&&
3622 (view
->target
== PIPE_TEXTURE_2D
||
3623 view
->target
== PIPE_TEXTURE_RECT
);
3625 sview
->xpot
= util_logbase2( resource
->width0
);
3626 sview
->ypot
= util_logbase2( resource
->height0
);
3629 return (struct pipe_sampler_view
*) sview
;
3633 static inline const struct sp_tgsi_sampler
*
3634 sp_tgsi_sampler_cast_c(const struct tgsi_sampler
*sampler
)
3636 return (const struct sp_tgsi_sampler
*)sampler
;
3641 sp_tgsi_get_dims(struct tgsi_sampler
*tgsi_sampler
,
3642 const unsigned sview_index
,
3643 int level
, int dims
[4])
3645 const struct sp_tgsi_sampler
*sp_samp
=
3646 sp_tgsi_sampler_cast_c(tgsi_sampler
);
3648 assert(sview_index
< PIPE_MAX_SHADER_SAMPLER_VIEWS
);
3649 /* always have a view here but texture is NULL if no sampler view was set. */
3650 if (!sp_samp
->sp_sview
[sview_index
].base
.texture
) {
3651 dims
[0] = dims
[1] = dims
[2] = dims
[3] = 0;
3654 sp_get_dims(&sp_samp
->sp_sview
[sview_index
], level
, dims
);
3658 static void prepare_compare_values(enum pipe_texture_target target
,
3659 const float p
[TGSI_QUAD_SIZE
],
3660 const float c0
[TGSI_QUAD_SIZE
],
3661 const float c1
[TGSI_QUAD_SIZE
],
3662 float pc
[TGSI_QUAD_SIZE
])
3664 if (target
== PIPE_TEXTURE_2D_ARRAY
||
3665 target
== PIPE_TEXTURE_CUBE
) {
3670 } else if (target
== PIPE_TEXTURE_CUBE_ARRAY
) {
3684 sp_tgsi_get_samples(struct tgsi_sampler
*tgsi_sampler
,
3685 const unsigned sview_index
,
3686 const unsigned sampler_index
,
3687 const float s
[TGSI_QUAD_SIZE
],
3688 const float t
[TGSI_QUAD_SIZE
],
3689 const float p
[TGSI_QUAD_SIZE
],
3690 const float c0
[TGSI_QUAD_SIZE
],
3691 const float lod_in
[TGSI_QUAD_SIZE
],
3692 float derivs
[3][2][TGSI_QUAD_SIZE
],
3693 const int8_t offset
[3],
3694 enum tgsi_sampler_control control
,
3695 float rgba
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
])
3697 const struct sp_tgsi_sampler
*sp_tgsi_samp
=
3698 sp_tgsi_sampler_cast_c(tgsi_sampler
);
3699 const struct sp_sampler_view
*sp_sview
;
3700 const struct sp_sampler
*sp_samp
;
3701 struct filter_args filt_args
;
3702 float compare_values
[TGSI_QUAD_SIZE
];
3703 float lod
[TGSI_QUAD_SIZE
];
3705 assert(sview_index
< PIPE_MAX_SHADER_SAMPLER_VIEWS
);
3706 assert(sampler_index
< PIPE_MAX_SAMPLERS
);
3707 assert(sp_tgsi_samp
->sp_sampler
[sampler_index
]);
3709 sp_sview
= &sp_tgsi_samp
->sp_sview
[sview_index
];
3710 sp_samp
= sp_tgsi_samp
->sp_sampler
[sampler_index
];
3711 /* always have a view here but texture is NULL if no sampler view was set. */
3712 if (!sp_sview
->base
.texture
) {
3714 for (j
= 0; j
< TGSI_NUM_CHANNELS
; j
++) {
3715 for (i
= 0; i
< TGSI_QUAD_SIZE
; i
++) {
3722 if (sp_samp
->base
.compare_mode
!= PIPE_TEX_COMPARE_NONE
)
3723 prepare_compare_values(sp_sview
->base
.target
, p
, c0
, lod_in
, compare_values
);
3725 filt_args
.control
= control
;
3726 filt_args
.offset
= offset
;
3727 int gather_comp
= get_gather_component(lod_in
);
3729 compute_lambda_lod(sp_sview
,sp_samp
, s
, t
, p
, derivs
, lod_in
, control
, lod
);
3731 if (sp_sview
->need_cube_convert
) {
3732 float cs
[TGSI_QUAD_SIZE
];
3733 float ct
[TGSI_QUAD_SIZE
];
3734 float cp
[TGSI_QUAD_SIZE
];
3735 uint faces
[TGSI_QUAD_SIZE
];
3737 convert_cube(sp_sview
, sp_samp
, s
, t
, p
, c0
, cs
, ct
, cp
, faces
);
3739 filt_args
.faces
= faces
;
3740 sample_mip(sp_sview
, sp_samp
, cs
, ct
, cp
, compare_values
, gather_comp
, lod
, &filt_args
, rgba
);
3742 static const uint zero_faces
[TGSI_QUAD_SIZE
] = {0, 0, 0, 0};
3744 filt_args
.faces
= zero_faces
;
3745 sample_mip(sp_sview
, sp_samp
, s
, t
, p
, compare_values
, gather_comp
, lod
, &filt_args
, rgba
);
3750 sp_tgsi_query_lod(const struct tgsi_sampler
*tgsi_sampler
,
3751 const unsigned sview_index
,
3752 const unsigned sampler_index
,
3753 const float s
[TGSI_QUAD_SIZE
],
3754 const float t
[TGSI_QUAD_SIZE
],
3755 const float p
[TGSI_QUAD_SIZE
],
3756 const float c0
[TGSI_QUAD_SIZE
],
3757 const enum tgsi_sampler_control control
,
3758 float mipmap
[TGSI_QUAD_SIZE
],
3759 float lod
[TGSI_QUAD_SIZE
])
3761 static const float lod_in
[TGSI_QUAD_SIZE
] = { 0.0, 0.0, 0.0, 0.0 };
3762 static const float dummy_grad
[3][2][TGSI_QUAD_SIZE
];
3764 const struct sp_tgsi_sampler
*sp_tgsi_samp
=
3765 sp_tgsi_sampler_cast_c(tgsi_sampler
);
3766 const struct sp_sampler_view
*sp_sview
;
3767 const struct sp_sampler
*sp_samp
;
3768 const struct sp_filter_funcs
*funcs
;
3771 assert(sview_index
< PIPE_MAX_SHADER_SAMPLER_VIEWS
);
3772 assert(sampler_index
< PIPE_MAX_SAMPLERS
);
3773 assert(sp_tgsi_samp
->sp_sampler
[sampler_index
]);
3775 sp_sview
= &sp_tgsi_samp
->sp_sview
[sview_index
];
3776 sp_samp
= sp_tgsi_samp
->sp_sampler
[sampler_index
];
3777 /* always have a view here but texture is NULL if no sampler view was
3779 if (!sp_sview
->base
.texture
) {
3780 for (i
= 0; i
< TGSI_QUAD_SIZE
; i
++) {
3786 compute_lambda_lod_unclamped(sp_sview
, sp_samp
,
3787 s
, t
, p
, dummy_grad
, lod_in
, control
, lod
);
3789 get_filters(sp_sview
, sp_samp
, control
, &funcs
, NULL
, NULL
);
3790 funcs
->relative_level(sp_sview
, sp_samp
, lod
, mipmap
);
3794 sp_tgsi_get_texel(struct tgsi_sampler
*tgsi_sampler
,
3795 const unsigned sview_index
,
3796 const int i
[TGSI_QUAD_SIZE
],
3797 const int j
[TGSI_QUAD_SIZE
], const int k
[TGSI_QUAD_SIZE
],
3798 const int lod
[TGSI_QUAD_SIZE
], const int8_t offset
[3],
3799 float rgba
[TGSI_NUM_CHANNELS
][TGSI_QUAD_SIZE
])
3801 const struct sp_tgsi_sampler
*sp_samp
=
3802 sp_tgsi_sampler_cast_c(tgsi_sampler
);
3804 assert(sview_index
< PIPE_MAX_SHADER_SAMPLER_VIEWS
);
3805 /* always have a view here but texture is NULL if no sampler view was set. */
3806 if (!sp_samp
->sp_sview
[sview_index
].base
.texture
) {
3808 for (j
= 0; j
< TGSI_NUM_CHANNELS
; j
++) {
3809 for (i
= 0; i
< TGSI_QUAD_SIZE
; i
++) {
3815 sp_get_texels(&sp_samp
->sp_sview
[sview_index
], i
, j
, k
, lod
, offset
, rgba
);
3819 struct sp_tgsi_sampler
*
3820 sp_create_tgsi_sampler(void)
3822 struct sp_tgsi_sampler
*samp
= CALLOC_STRUCT(sp_tgsi_sampler
);
3826 samp
->base
.get_dims
= sp_tgsi_get_dims
;
3827 samp
->base
.get_samples
= sp_tgsi_get_samples
;
3828 samp
->base
.get_texel
= sp_tgsi_get_texel
;
3829 samp
->base
.query_lod
= sp_tgsi_query_lod
;