1 /**************************************************************************
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
36 #include "main/macros.h"
37 #include "sp_context.h"
38 #include "sp_surface.h"
39 #include "sp_tex_sample.h"
40 #include "pipe/p_context.h"
41 #include "pipe/p_defines.h"
42 #include "pipe/tgsi/core/tgsi_exec.h"
46 * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes
47 * see 1-pixel bands of improperly weighted linear-filtered textures.
48 * The tests/texwrap.c demo is a good test.
49 * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
50 * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
52 #define FRAC(f) ((f) - IFLOOR(f))
56 * Linear interpolation macro
58 #define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) )
62 * Do 2D/biliner interpolation of float values.
63 * v00, v10, v01 and v11 are typically four texture samples in a square/box.
64 * a and b are the horizontal and vertical interpolants.
65 * It's important that this function is inlined when compiled with
66 * optimization! If we find that's not true on some systems, convert
70 lerp_2d(GLfloat a
, GLfloat b
,
71 GLfloat v00
, GLfloat v10
, GLfloat v01
, GLfloat v11
)
73 const GLfloat temp0
= LERP(a
, v00
, v10
);
74 const GLfloat temp1
= LERP(a
, v01
, v11
);
75 return LERP(b
, temp0
, temp1
);
80 * Compute the remainder of a divided by b, but be careful with
81 * negative values so that REPEAT mode works right.
84 repeat_remainder(GLint a
, GLint b
)
89 return (a
+ 1) % b
+ b
- 1;
94 * Apply texture coord wrapping mode and return integer texture index.
95 * \param wrapMode PIPE_TEX_WRAP_x
96 * \param s the texcoord
97 * \param size the texture image size
98 * \return integer texture index
101 nearest_texcoord(GLuint wrapMode
, GLfloat s
, GLuint size
)
105 case PIPE_TEX_WRAP_REPEAT
:
106 /* s limited to [0,1) */
107 /* i limited to [0,size-1] */
108 i
= IFLOOR(s
* size
);
109 i
= repeat_remainder(i
, size
);
111 case PIPE_TEX_WRAP_CLAMP
:
112 /* s limited to [0,1] */
113 /* i limited to [0,size-1] */
119 i
= IFLOOR(s
* size
);
121 case PIPE_TEX_WRAP_CLAMP_TO_EDGE
:
123 /* s limited to [min,max] */
124 /* i limited to [0, size-1] */
125 const GLfloat min
= 1.0F
/ (2.0F
* size
);
126 const GLfloat max
= 1.0F
- min
;
132 i
= IFLOOR(s
* size
);
135 case PIPE_TEX_WRAP_CLAMP_TO_BORDER
:
137 /* s limited to [min,max] */
138 /* i limited to [-1, size] */
139 const GLfloat min
= -1.0F
/ (2.0F
* size
);
140 const GLfloat max
= 1.0F
- min
;
146 i
= IFLOOR(s
* size
);
149 case PIPE_TEX_WRAP_MIRROR_REPEAT
:
151 const GLfloat min
= 1.0F
/ (2.0F
* size
);
152 const GLfloat max
= 1.0F
- min
;
153 const GLint flr
= IFLOOR(s
);
156 u
= 1.0F
- (s
- (GLfloat
) flr
);
158 u
= s
- (GLfloat
) flr
;
164 i
= IFLOOR(u
* size
);
167 case PIPE_TEX_WRAP_MIRROR_CLAMP
:
169 /* s limited to [0,1] */
170 /* i limited to [0,size-1] */
171 const GLfloat u
= FABSF(s
);
177 i
= IFLOOR(u
* size
);
180 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE
:
182 /* s limited to [min,max] */
183 /* i limited to [0, size-1] */
184 const GLfloat min
= 1.0F
/ (2.0F
* size
);
185 const GLfloat max
= 1.0F
- min
;
186 const GLfloat u
= FABSF(s
);
192 i
= IFLOOR(u
* size
);
195 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER
:
197 /* s limited to [min,max] */
198 /* i limited to [0, size-1] */
199 const GLfloat min
= -1.0F
/ (2.0F
* size
);
200 const GLfloat max
= 1.0F
- min
;
201 const GLfloat u
= FABSF(s
);
207 i
= IFLOOR(u
* size
);
218 * Used to compute texel locations for linear sampling.
219 * \param wrapMode PIPE_TEX_WRAP_x
220 * \param s the texcoord
221 * \param size the texture image size
222 * \param i0 returns first texture index
223 * \param i1 returns second texture index (usually *i0 + 1)
224 * \param a returns blend factor/weight between texture indexes
227 linear_texcoord(GLuint wrapMode
, GLfloat s
, GLuint size
,
228 GLint
*i0
, GLint
*i1
, GLfloat
*a
)
232 case PIPE_TEX_WRAP_REPEAT
:
234 *i0
= repeat_remainder(IFLOOR(u
), size
);
235 *i1
= repeat_remainder(*i0
+ 1, size
);
237 case PIPE_TEX_WRAP_CLAMP
:
248 case PIPE_TEX_WRAP_CLAMP_TO_EDGE
:
260 if (*i1
>= (GLint
) size
)
263 case PIPE_TEX_WRAP_CLAMP_TO_BORDER
:
265 const GLfloat min
= -1.0F
/ (2.0F
* size
);
266 const GLfloat max
= 1.0F
- min
;
278 case PIPE_TEX_WRAP_MIRROR_REPEAT
:
280 const GLint flr
= IFLOOR(s
);
282 u
= 1.0F
- (s
- (GLfloat
) flr
);
284 u
= s
- (GLfloat
) flr
;
285 u
= (u
* size
) - 0.5F
;
290 if (*i1
>= (GLint
) size
)
294 case PIPE_TEX_WRAP_MIRROR_CLAMP
:
304 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE
:
315 if (*i1
>= (GLint
) size
)
318 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER
:
320 const GLfloat min
= -1.0F
/ (2.0F
* size
);
321 const GLfloat max
= 1.0F
- min
;
342 choose_cube_face(const GLfloat texcoord
[4], GLfloat newCoord
[4])
346 direction target sc tc ma
347 ---------- ------------------------------- --- --- ---
348 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
349 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
350 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
351 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
352 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
353 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
355 const GLfloat rx
= texcoord
[0];
356 const GLfloat ry
= texcoord
[1];
357 const GLfloat rz
= texcoord
[2];
358 const GLfloat arx
= FABSF(rx
), ary
= FABSF(ry
), arz
= FABSF(rz
);
362 if (arx
> ary
&& arx
> arz
) {
364 face
= PIPE_TEX_FACE_POS_X
;
370 face
= PIPE_TEX_FACE_NEG_X
;
376 else if (ary
> arx
&& ary
> arz
) {
378 face
= PIPE_TEX_FACE_POS_Y
;
384 face
= PIPE_TEX_FACE_NEG_Y
;
392 face
= PIPE_TEX_FACE_POS_Z
;
398 face
= PIPE_TEX_FACE_NEG_Z
;
405 newCoord
[0] = ( sc
/ ma
+ 1.0F
) * 0.5F
;
406 newCoord
[1] = ( tc
/ ma
+ 1.0F
) * 0.5F
;
413 sp_get_sample_1d(struct tgsi_sampler
*sampler
,
414 const GLfloat strq
[4], GLfloat lambda
, GLfloat rgba
[4])
416 struct pipe_context
*pipe
= (struct pipe_context
*) sampler
->pipe
;
417 struct pipe_surface
*ps
418 = pipe
->get_tex_surface(pipe
, sampler
->texture
, 0, 0, 0);
420 switch (sampler
->state
->min_img_filter
) {
421 case PIPE_TEX_FILTER_NEAREST
:
424 x
= nearest_texcoord(sampler
->state
->wrap_s
, strq
[0],
425 sampler
->texture
->width0
);
426 ps
->get_tile(ps
, x
, 0, 1, 1, rgba
);
429 case PIPE_TEX_FILTER_LINEAR
:
431 GLfloat t0
[4], t1
[4];
434 linear_texcoord(sampler
->state
->wrap_s
, strq
[0],
435 sampler
->texture
->width0
, &x0
, &x1
, &a
);
436 ps
->get_tile(ps
, x0
, 0, 1, 1, t0
);
437 ps
->get_tile(ps
, x1
, 0, 1, 1, t1
);
439 rgba
[0] = LERP(a
, t0
[0], t1
[0]);
440 rgba
[1] = LERP(a
, t0
[1], t1
[1]);
441 rgba
[2] = LERP(a
, t0
[2], t1
[2]);
442 rgba
[3] = LERP(a
, t0
[3], t1
[3]);
451 choose_mipmap_level(struct tgsi_sampler
*sampler
, GLfloat lambda
)
453 if (sampler
->state
->min_mip_filter
== PIPE_TEX_MIPFILTER_NONE
) {
457 GLint level
= (int) lambda
;
458 level
= CLAMP(level
, sampler
->texture
->first_level
,
459 sampler
->texture
->last_level
);
466 * Called via tgsi_sampler::get_sample()
467 * Use the sampler's state setting to get a filtered RGBA value
468 * from the sampler's texture (mipmap tree).
470 * XXX we can implement many versions of this function, each
471 * tightly coded for a specific combination of sampler state
472 * (nearest + repeat), (bilinear mipmap + clamp), etc.
474 * The update_samplers() function in st_atom_sampler.c could create
475 * a new tgsi_sampler object for each state combo it finds....
478 sp_get_sample_2d(struct tgsi_sampler
*sampler
,
479 const GLfloat strq
[4], GLfloat lambda
, GLfloat rgba
[4])
481 struct pipe_context
*pipe
= (struct pipe_context
*) sampler
->pipe
;
486 filter
= sampler
->state
->mag_img_filter
;
488 filter
= sampler
->state
->min_img_filter
;
490 level0
= choose_mipmap_level(sampler
, lambda
);
493 case PIPE_TEX_FILTER_NEAREST
:
495 GLint x
= nearest_texcoord(sampler
->state
->wrap_s
, strq
[0],
496 sampler
->texture
->level
[level0
].width
);
497 GLint y
= nearest_texcoord(sampler
->state
->wrap_t
, strq
[1],
498 sampler
->texture
->level
[level0
].height
);
499 GLint cx
= x
/ SAMPLER_CACHE_SIZE
;
500 GLint cy
= y
/ SAMPLER_CACHE_SIZE
;
501 if (cx
!= sampler
->cache_x
|| cy
!= sampler
->cache_y
||
502 level0
!= sampler
->cache_level
) {
503 /* cache miss, replace cache with new tile */
504 struct pipe_surface
*ps
505 = pipe
->get_tex_surface(pipe
, sampler
->texture
, 0, level0
, 0);
506 assert(ps
->width
== sampler
->texture
->level
[level0
].width
);
507 assert(ps
->height
== sampler
->texture
->level
[level0
].height
);
508 sampler
->cache_level
= level0
;
509 sampler
->cache_x
= cx
;
510 sampler
->cache_y
= cy
;
512 cx
* SAMPLER_CACHE_SIZE
,
513 cy
* SAMPLER_CACHE_SIZE
,
514 SAMPLER_CACHE_SIZE
, SAMPLER_CACHE_SIZE
,
515 (GLfloat
*) sampler
->cache
);
516 /*printf("cache miss (%d, %d)\n", x, y);*/
519 /*printf("cache hit (%d, %d)\n", x, y);*/
521 /* get texel from cache */
522 cx
= x
% SAMPLER_CACHE_SIZE
;
523 cy
= y
% SAMPLER_CACHE_SIZE
;
524 COPY_4V(rgba
, sampler
->cache
[cy
][cx
]);
527 case PIPE_TEX_FILTER_LINEAR
:
529 GLfloat t00
[4], t01
[4], t10
[4], t11
[4];
530 GLint x0
, y0
, x1
, y1
;
532 struct pipe_surface
*ps
533 = pipe
->get_tex_surface(pipe
, sampler
->texture
, 0, level0
, 0);
535 linear_texcoord(sampler
->state
->wrap_s
, strq
[0],
536 sampler
->texture
->width0
, &x0
, &x1
, &a
);
537 linear_texcoord(sampler
->state
->wrap_t
, strq
[1],
538 sampler
->texture
->height0
, &y0
, &y1
, &b
);
539 ps
->get_tile(ps
, x0
, y0
, 1, 1, t00
);
540 ps
->get_tile(ps
, x1
, y0
, 1, 1, t10
);
541 ps
->get_tile(ps
, x0
, y1
, 1, 1, t01
);
542 ps
->get_tile(ps
, x1
, y1
, 1, 1, t11
);
544 rgba
[0] = lerp_2d(a
, b
, t00
[0], t10
[0], t01
[0], t11
[0]);
545 rgba
[1] = lerp_2d(a
, b
, t00
[1], t10
[1], t01
[1], t11
[1]);
546 rgba
[2] = lerp_2d(a
, b
, t00
[2], t10
[2], t01
[2], t11
[2]);
547 rgba
[3] = lerp_2d(a
, b
, t00
[3], t10
[3], t01
[3], t11
[3]);
552 GLuint level0, level1;
553 level0 = choose_mipmap_level(sampler, lambda);
564 sp_get_sample_3d(struct tgsi_sampler
*sampler
,
565 const GLfloat strq
[4], GLfloat lamba
, GLfloat rgba
[4])
567 /* get/map pipe_surfaces corresponding to 3D tex slices */
572 sp_get_sample_cube(struct tgsi_sampler
*sampler
,
573 const GLfloat strq
[4], GLfloat lambda
, GLfloat rgba
[4])
576 GLuint face
= choose_cube_face(strq
, st
);
578 /* get/map surface corresponding to the face */
583 sp_get_sample(struct tgsi_sampler
*sampler
,
584 const GLfloat strq
[4], GLfloat lambda
, GLfloat rgba
[4])
586 switch (sampler
->texture
->target
) {
588 sp_get_sample_1d(sampler
, strq
, lambda
, rgba
);
591 sp_get_sample_2d(sampler
, strq
, lambda
, rgba
);
594 sp_get_sample_3d(sampler
, strq
, lambda
, rgba
);
596 case GL_TEXTURE_CUBE_MAP
:
597 sp_get_sample_cube(sampler
, strq
, lambda
, rgba
);