1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 #include "c99_math.h"
27 #include "main/glheader.h"
28 #include "main/context.h"
29
30 #include "main/macros.h"
31 #include "main/samplerobj.h"
32 #include "main/teximage.h"
33 #include "main/texobj.h"
34
35 #include "s_context.h"
36 #include "s_texfilter.h"
37
38
39 /*
40 * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes
41 * see 1-pixel bands of improperly weighted linear-filtered textures.
42 * The tests/texwrap.c demo is a good test.
43 * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
44 * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
45 */
46 #define FRAC(f) ((f) - util_ifloor(f))
47
48
49
50 /**
51 * Linear interpolation macro
52 */
53 #define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) )
54
55
56 /**
57 * Do 2D/biliner interpolation of float values.
58 * v00, v10, v01 and v11 are typically four texture samples in a square/box.
59 * a and b are the horizontal and vertical interpolants.
60 * It's important that this function is inlined when compiled with
61 * optimization! If we find that's not true on some systems, convert
62 * to a macro.
63 */
64 static inline GLfloat
lerp_2d(GLfloat a,GLfloat b,GLfloat v00,GLfloat v10,GLfloat v01,GLfloat v11)65 lerp_2d(GLfloat a, GLfloat b,
66 GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11)
67 {
68 const GLfloat temp0 = LERP(a, v00, v10);
69 const GLfloat temp1 = LERP(a, v01, v11);
70 return LERP(b, temp0, temp1);
71 }
72
73
74 /**
75 * Do 3D/trilinear interpolation of float values.
76 * \sa lerp_2d
77 */
78 static GLfloat
lerp_3d(GLfloat a,GLfloat b,GLfloat c,GLfloat v000,GLfloat v100,GLfloat v010,GLfloat v110,GLfloat v001,GLfloat v101,GLfloat v011,GLfloat v111)79 lerp_3d(GLfloat a, GLfloat b, GLfloat c,
80 GLfloat v000, GLfloat v100, GLfloat v010, GLfloat v110,
81 GLfloat v001, GLfloat v101, GLfloat v011, GLfloat v111)
82 {
83 const GLfloat temp00 = LERP(a, v000, v100);
84 const GLfloat temp10 = LERP(a, v010, v110);
85 const GLfloat temp01 = LERP(a, v001, v101);
86 const GLfloat temp11 = LERP(a, v011, v111);
87 const GLfloat temp0 = LERP(b, temp00, temp10);
88 const GLfloat temp1 = LERP(b, temp01, temp11);
89 return LERP(c, temp0, temp1);
90 }
91
92
93 /**
94 * Do linear interpolation of colors.
95 */
96 static void
lerp_rgba(GLfloat result[4],GLfloat t,const GLfloat a[4],const GLfloat b[4])97 lerp_rgba(GLfloat result[4], GLfloat t, const GLfloat a[4], const GLfloat b[4])
98 {
99 result[0] = LERP(t, a[0], b[0]);
100 result[1] = LERP(t, a[1], b[1]);
101 result[2] = LERP(t, a[2], b[2]);
102 result[3] = LERP(t, a[3], b[3]);
103 }
104
105
106 /**
107 * Do bilinear interpolation of colors.
108 */
109 static void
lerp_rgba_2d(GLfloat result[4],GLfloat a,GLfloat b,const GLfloat t00[4],const GLfloat t10[4],const GLfloat t01[4],const GLfloat t11[4])110 lerp_rgba_2d(GLfloat result[4], GLfloat a, GLfloat b,
111 const GLfloat t00[4], const GLfloat t10[4],
112 const GLfloat t01[4], const GLfloat t11[4])
113 {
114 result[0] = lerp_2d(a, b, t00[0], t10[0], t01[0], t11[0]);
115 result[1] = lerp_2d(a, b, t00[1], t10[1], t01[1], t11[1]);
116 result[2] = lerp_2d(a, b, t00[2], t10[2], t01[2], t11[2]);
117 result[3] = lerp_2d(a, b, t00[3], t10[3], t01[3], t11[3]);
118 }
119
120
121 /**
122 * Do trilinear interpolation of colors.
123 */
124 static void
lerp_rgba_3d(GLfloat result[4],GLfloat a,GLfloat b,GLfloat c,const GLfloat t000[4],const GLfloat t100[4],const GLfloat t010[4],const GLfloat t110[4],const GLfloat t001[4],const GLfloat t101[4],const GLfloat t011[4],const GLfloat t111[4])125 lerp_rgba_3d(GLfloat result[4], GLfloat a, GLfloat b, GLfloat c,
126 const GLfloat t000[4], const GLfloat t100[4],
127 const GLfloat t010[4], const GLfloat t110[4],
128 const GLfloat t001[4], const GLfloat t101[4],
129 const GLfloat t011[4], const GLfloat t111[4])
130 {
131 GLuint k;
132 /* compiler should unroll these short loops */
133 for (k = 0; k < 4; k++) {
134 result[k] = lerp_3d(a, b, c, t000[k], t100[k], t010[k], t110[k],
135 t001[k], t101[k], t011[k], t111[k]);
136 }
137 }
138
139
140 /**
141 * Used for GL_REPEAT wrap mode. Using A % B doesn't produce the
142 * right results for A<0. Casting to A to be unsigned only works if B
143 * is a power of two. Adding a bias to A (which is a multiple of B)
144 * avoids the problems with A < 0 (for reasonable A) without using a
145 * conditional.
146 */
147 #define REMAINDER(A, B) (((A) + (B) * 1024) % (B))
148
149
150 /**
151 * Used to compute texel locations for linear sampling.
152 * Input:
153 * wrapMode = GL_REPEAT, GL_CLAMP, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER
154 * s = texcoord in [0,1]
155 * size = width (or height or depth) of texture
156 * Output:
157 * i0, i1 = returns two nearest texel indexes
158 * weight = returns blend factor between texels
159 */
160 static void
linear_texel_locations(GLenum wrapMode,const struct gl_texture_image * img,GLint size,GLfloat s,GLint * i0,GLint * i1,GLfloat * weight)161 linear_texel_locations(GLenum wrapMode,
162 const struct gl_texture_image *img,
163 GLint size, GLfloat s,
164 GLint *i0, GLint *i1, GLfloat *weight)
165 {
166 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
167 GLfloat u;
168 switch (wrapMode) {
169 case GL_REPEAT:
170 u = s * size - 0.5F;
171 if (swImg->_IsPowerOfTwo) {
172 *i0 = util_ifloor(u) & (size - 1);
173 *i1 = (*i0 + 1) & (size - 1);
174 }
175 else {
176 *i0 = REMAINDER(util_ifloor(u), size);
177 *i1 = REMAINDER(*i0 + 1, size);
178 }
179 break;
180 case GL_CLAMP_TO_EDGE:
181 if (s <= 0.0F)
182 u = 0.0F;
183 else if (s >= 1.0F)
184 u = (GLfloat) size;
185 else
186 u = s * size;
187 u -= 0.5F;
188 *i0 = util_ifloor(u);
189 *i1 = *i0 + 1;
190 if (*i0 < 0)
191 *i0 = 0;
192 if (*i1 >= (GLint) size)
193 *i1 = size - 1;
194 break;
195 case GL_CLAMP_TO_BORDER:
196 {
197 const GLfloat min = -1.0F / (2.0F * size);
198 const GLfloat max = 1.0F - min;
199 if (s <= min)
200 u = min * size;
201 else if (s >= max)
202 u = max * size;
203 else
204 u = s * size;
205 u -= 0.5F;
206 *i0 = util_ifloor(u);
207 *i1 = *i0 + 1;
208 }
209 break;
210 case GL_MIRRORED_REPEAT:
211 {
212 const GLint flr = util_ifloor(s);
213 if (flr & 1)
214 u = 1.0F - (s - (GLfloat) flr);
215 else
216 u = s - (GLfloat) flr;
217 u = (u * size) - 0.5F;
218 *i0 = util_ifloor(u);
219 *i1 = *i0 + 1;
220 if (*i0 < 0)
221 *i0 = 0;
222 if (*i1 >= (GLint) size)
223 *i1 = size - 1;
224 }
225 break;
226 case GL_MIRROR_CLAMP_EXT:
227 u = fabsf(s);
228 if (u >= 1.0F)
229 u = (GLfloat) size;
230 else
231 u *= size;
232 u -= 0.5F;
233 *i0 = util_ifloor(u);
234 *i1 = *i0 + 1;
235 break;
236 case GL_MIRROR_CLAMP_TO_EDGE_EXT:
237 u = fabsf(s);
238 if (u >= 1.0F)
239 u = (GLfloat) size;
240 else
241 u *= size;
242 u -= 0.5F;
243 *i0 = util_ifloor(u);
244 *i1 = *i0 + 1;
245 if (*i0 < 0)
246 *i0 = 0;
247 if (*i1 >= (GLint) size)
248 *i1 = size - 1;
249 break;
250 case GL_MIRROR_CLAMP_TO_BORDER_EXT:
251 {
252 const GLfloat min = -1.0F / (2.0F * size);
253 const GLfloat max = 1.0F - min;
254 u = fabsf(s);
255 if (u <= min)
256 u = min * size;
257 else if (u >= max)
258 u = max * size;
259 else
260 u *= size;
261 u -= 0.5F;
262 *i0 = util_ifloor(u);
263 *i1 = *i0 + 1;
264 }
265 break;
266 case GL_CLAMP:
267 if (s <= 0.0F)
268 u = 0.0F;
269 else if (s >= 1.0F)
270 u = (GLfloat) size;
271 else
272 u = s * size;
273 u -= 0.5F;
274 *i0 = util_ifloor(u);
275 *i1 = *i0 + 1;
276 break;
277 default:
278 _mesa_problem(NULL, "Bad wrap mode");
279 *i0 = *i1 = 0;
280 u = 0.0F;
281 break;
282 }
283 *weight = FRAC(u);
284 }
285
286
287 /**
288 * Used to compute texel location for nearest sampling.
289 */
290 static GLint
nearest_texel_location(GLenum wrapMode,const struct gl_texture_image * img,GLint size,GLfloat s)291 nearest_texel_location(GLenum wrapMode,
292 const struct gl_texture_image *img,
293 GLint size, GLfloat s)
294 {
295 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
296 GLint i;
297
298 switch (wrapMode) {
299 case GL_REPEAT:
300 /* s limited to [0,1) */
301 /* i limited to [0,size-1] */
302 i = util_ifloor(s * size);
303 if (swImg->_IsPowerOfTwo)
304 i &= (size - 1);
305 else
306 i = REMAINDER(i, size);
307 return i;
308 case GL_CLAMP_TO_EDGE:
309 {
310 /* s limited to [min,max] */
311 /* i limited to [0, size-1] */
312 const GLfloat min = 1.0F / (2.0F * size);
313 const GLfloat max = 1.0F - min;
314 if (s < min)
315 i = 0;
316 else if (s > max)
317 i = size - 1;
318 else
319 i = util_ifloor(s * size);
320 }
321 return i;
322 case GL_CLAMP_TO_BORDER:
323 {
324 /* s limited to [min,max] */
325 /* i limited to [-1, size] */
326 const GLfloat min = -1.0F / (2.0F * size);
327 const GLfloat max = 1.0F - min;
328 if (s <= min)
329 i = -1;
330 else if (s >= max)
331 i = size;
332 else
333 i = util_ifloor(s * size);
334 }
335 return i;
336 case GL_MIRRORED_REPEAT:
337 {
338 const GLfloat min = 1.0F / (2.0F * size);
339 const GLfloat max = 1.0F - min;
340 const GLint flr = util_ifloor(s);
341 GLfloat u;
342 if (flr & 1)
343 u = 1.0F - (s - (GLfloat) flr);
344 else
345 u = s - (GLfloat) flr;
346 if (u < min)
347 i = 0;
348 else if (u > max)
349 i = size - 1;
350 else
351 i = util_ifloor(u * size);
352 }
353 return i;
354 case GL_MIRROR_CLAMP_EXT:
355 {
356 /* s limited to [0,1] */
357 /* i limited to [0,size-1] */
358 const GLfloat u = fabsf(s);
359 if (u <= 0.0F)
360 i = 0;
361 else if (u >= 1.0F)
362 i = size - 1;
363 else
364 i = util_ifloor(u * size);
365 }
366 return i;
367 case GL_MIRROR_CLAMP_TO_EDGE_EXT:
368 {
369 /* s limited to [min,max] */
370 /* i limited to [0, size-1] */
371 const GLfloat min = 1.0F / (2.0F * size);
372 const GLfloat max = 1.0F - min;
373 const GLfloat u = fabsf(s);
374 if (u < min)
375 i = 0;
376 else if (u > max)
377 i = size - 1;
378 else
379 i = util_ifloor(u * size);
380 }
381 return i;
382 case GL_MIRROR_CLAMP_TO_BORDER_EXT:
383 {
384 /* s limited to [min,max] */
385 /* i limited to [0, size-1] */
386 const GLfloat min = -1.0F / (2.0F * size);
387 const GLfloat max = 1.0F - min;
388 const GLfloat u = fabsf(s);
389 if (u < min)
390 i = -1;
391 else if (u > max)
392 i = size;
393 else
394 i = util_ifloor(u * size);
395 }
396 return i;
397 case GL_CLAMP:
398 /* s limited to [0,1] */
399 /* i limited to [0,size-1] */
400 if (s <= 0.0F)
401 i = 0;
402 else if (s >= 1.0F)
403 i = size - 1;
404 else
405 i = util_ifloor(s * size);
406 return i;
407 default:
408 _mesa_problem(NULL, "Bad wrap mode");
409 return 0;
410 }
411 }
412
413
414 /* Power of two image sizes only */
415 static void
linear_repeat_texel_location(GLuint size,GLfloat s,GLint * i0,GLint * i1,GLfloat * weight)416 linear_repeat_texel_location(GLuint size, GLfloat s,
417 GLint *i0, GLint *i1, GLfloat *weight)
418 {
419 GLfloat u = s * size - 0.5F;
420 *i0 = util_ifloor(u) & (size - 1);
421 *i1 = (*i0 + 1) & (size - 1);
422 *weight = FRAC(u);
423 }
424
425
426 /**
427 * Do clamp/wrap for a texture rectangle coord, GL_NEAREST filter mode.
428 */
429 static GLint
clamp_rect_coord_nearest(GLenum wrapMode,GLfloat coord,GLint max)430 clamp_rect_coord_nearest(GLenum wrapMode, GLfloat coord, GLint max)
431 {
432 switch (wrapMode) {
433 case GL_CLAMP:
434 return util_ifloor( CLAMP(coord, 0.0F, max - 1) );
435 case GL_CLAMP_TO_EDGE:
436 return util_ifloor( CLAMP(coord, 0.5F, max - 0.5F) );
437 case GL_CLAMP_TO_BORDER:
438 return util_ifloor( CLAMP(coord, -0.5F, max + 0.5F) );
439 default:
440 _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_nearest");
441 return 0;
442 }
443 }
444
445
446 /**
447 * As above, but GL_LINEAR filtering.
448 */
449 static void
clamp_rect_coord_linear(GLenum wrapMode,GLfloat coord,GLint max,GLint * i0out,GLint * i1out,GLfloat * weight)450 clamp_rect_coord_linear(GLenum wrapMode, GLfloat coord, GLint max,
451 GLint *i0out, GLint *i1out, GLfloat *weight)
452 {
453 GLfloat fcol;
454 GLint i0, i1;
455 switch (wrapMode) {
456 case GL_CLAMP:
457 /* Not exactly what the spec says, but it matches NVIDIA output */
458 fcol = CLAMP(coord - 0.5F, 0.0F, max - 1);
459 i0 = util_ifloor(fcol);
460 i1 = i0 + 1;
461 break;
462 case GL_CLAMP_TO_EDGE:
463 fcol = CLAMP(coord, 0.5F, max - 0.5F);
464 fcol -= 0.5F;
465 i0 = util_ifloor(fcol);
466 i1 = i0 + 1;
467 if (i1 > max - 1)
468 i1 = max - 1;
469 break;
470 case GL_CLAMP_TO_BORDER:
471 fcol = CLAMP(coord, -0.5F, max + 0.5F);
472 fcol -= 0.5F;
473 i0 = util_ifloor(fcol);
474 i1 = i0 + 1;
475 break;
476 default:
477 _mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_linear");
478 i0 = i1 = 0;
479 fcol = 0.0F;
480 break;
481 }
482 *i0out = i0;
483 *i1out = i1;
484 *weight = FRAC(fcol);
485 }
486
487
488 /**
489 * Compute slice/image to use for 1D or 2D array texture.
490 */
491 static GLint
tex_array_slice(GLfloat coord,GLsizei size)492 tex_array_slice(GLfloat coord, GLsizei size)
493 {
494 GLint slice = util_ifloor(coord + 0.5f);
495 slice = CLAMP(slice, 0, size - 1);
496 return slice;
497 }
498
499
500 /**
501 * Compute nearest integer texcoords for given texobj and coordinate.
502 * NOTE: only used for depth texture sampling.
503 */
504 static void
nearest_texcoord(const struct gl_sampler_object * samp,const struct gl_texture_object * texObj,GLuint level,const GLfloat texcoord[4],GLint * i,GLint * j,GLint * k)505 nearest_texcoord(const struct gl_sampler_object *samp,
506 const struct gl_texture_object *texObj,
507 GLuint level,
508 const GLfloat texcoord[4],
509 GLint *i, GLint *j, GLint *k)
510 {
511 const struct gl_texture_image *img = texObj->Image[0][level];
512 const GLint width = img->Width;
513 const GLint height = img->Height;
514 const GLint depth = img->Depth;
515
516 switch (texObj->Target) {
517 case GL_TEXTURE_RECTANGLE_ARB:
518 *i = clamp_rect_coord_nearest(samp->WrapS, texcoord[0], width);
519 *j = clamp_rect_coord_nearest(samp->WrapT, texcoord[1], height);
520 *k = 0;
521 break;
522 case GL_TEXTURE_1D:
523 *i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
524 *j = 0;
525 *k = 0;
526 break;
527 case GL_TEXTURE_2D:
528 *i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
529 *j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
530 *k = 0;
531 break;
532 case GL_TEXTURE_1D_ARRAY_EXT:
533 *i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
534 *j = tex_array_slice(texcoord[1], height);
535 *k = 0;
536 break;
537 case GL_TEXTURE_2D_ARRAY_EXT:
538 *i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
539 *j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
540 *k = tex_array_slice(texcoord[2], depth);
541 break;
542 default:
543 *i = *j = *k = 0;
544 break;
545 }
546 }
547
548
549 /**
550 * Compute linear integer texcoords for given texobj and coordinate.
551 * NOTE: only used for depth texture sampling.
552 */
553 static void
linear_texcoord(const struct gl_sampler_object * samp,const struct gl_texture_object * texObj,GLuint level,const GLfloat texcoord[4],GLint * i0,GLint * i1,GLint * j0,GLint * j1,GLint * slice,GLfloat * wi,GLfloat * wj)554 linear_texcoord(const struct gl_sampler_object *samp,
555 const struct gl_texture_object *texObj,
556 GLuint level,
557 const GLfloat texcoord[4],
558 GLint *i0, GLint *i1, GLint *j0, GLint *j1, GLint *slice,
559 GLfloat *wi, GLfloat *wj)
560 {
561 const struct gl_texture_image *img = texObj->Image[0][level];
562 const GLint width = img->Width;
563 const GLint height = img->Height;
564 const GLint depth = img->Depth;
565
566 switch (texObj->Target) {
567 case GL_TEXTURE_RECTANGLE_ARB:
568 clamp_rect_coord_linear(samp->WrapS, texcoord[0],
569 width, i0, i1, wi);
570 clamp_rect_coord_linear(samp->WrapT, texcoord[1],
571 height, j0, j1, wj);
572 *slice = 0;
573 break;
574
575 case GL_TEXTURE_1D:
576 case GL_TEXTURE_2D:
577 linear_texel_locations(samp->WrapS, img, width,
578 texcoord[0], i0, i1, wi);
579 linear_texel_locations(samp->WrapT, img, height,
580 texcoord[1], j0, j1, wj);
581 *slice = 0;
582 break;
583
584 case GL_TEXTURE_1D_ARRAY_EXT:
585 linear_texel_locations(samp->WrapS, img, width,
586 texcoord[0], i0, i1, wi);
587 *j0 = tex_array_slice(texcoord[1], height);
588 *j1 = *j0;
589 *slice = 0;
590 break;
591
592 case GL_TEXTURE_2D_ARRAY_EXT:
593 linear_texel_locations(samp->WrapS, img, width,
594 texcoord[0], i0, i1, wi);
595 linear_texel_locations(samp->WrapT, img, height,
596 texcoord[1], j0, j1, wj);
597 *slice = tex_array_slice(texcoord[2], depth);
598 break;
599
600 default:
601 *slice = 0;
602 break;
603 }
604 }
605
606
607
608 /**
609 * For linear interpolation between mipmap levels N and N+1, this function
610 * computes N.
611 */
612 static GLint
linear_mipmap_level(const struct gl_texture_object * tObj,GLfloat lambda)613 linear_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda)
614 {
615 if (lambda < 0.0F)
616 return tObj->BaseLevel;
617 else if (lambda > tObj->_MaxLambda)
618 return (GLint) (tObj->BaseLevel + tObj->_MaxLambda);
619 else
620 return (GLint) (tObj->BaseLevel + lambda);
621 }
622
623
624 /**
625 * Compute the nearest mipmap level to take texels from.
626 */
627 static GLint
nearest_mipmap_level(const struct gl_texture_object * tObj,GLfloat lambda)628 nearest_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda)
629 {
630 GLfloat l;
631 GLint level;
632 if (lambda <= 0.5F)
633 l = 0.0F;
634 else if (lambda > tObj->_MaxLambda + 0.4999F)
635 l = tObj->_MaxLambda + 0.4999F;
636 else
637 l = lambda;
638 level = (GLint) (tObj->BaseLevel + l + 0.5F);
639 if (level > tObj->_MaxLevel)
640 level = tObj->_MaxLevel;
641 return level;
642 }
643
644
645
646 /*
647 * Bitflags for texture border color sampling.
648 */
649 #define I0BIT 1
650 #define I1BIT 2
651 #define J0BIT 4
652 #define J1BIT 8
653 #define K0BIT 16
654 #define K1BIT 32
655
656
657
658 /**
659 * The lambda[] array values are always monotonic. Either the whole span
660 * will be minified, magnified, or split between the two. This function
661 * determines the subranges in [0, n-1] that are to be minified or magnified.
662 */
663 static void
compute_min_mag_ranges(const struct gl_sampler_object * samp,GLuint n,const GLfloat lambda[],GLuint * minStart,GLuint * minEnd,GLuint * magStart,GLuint * magEnd)664 compute_min_mag_ranges(const struct gl_sampler_object *samp,
665 GLuint n, const GLfloat lambda[],
666 GLuint *minStart, GLuint *minEnd,
667 GLuint *magStart, GLuint *magEnd)
668 {
669 GLfloat minMagThresh;
670
671 /* we shouldn't be here if minfilter == magfilter */
672 assert(samp->MinFilter != samp->MagFilter);
673
674 /* This bit comes from the OpenGL spec: */
675 if (samp->MagFilter == GL_LINEAR
676 && (samp->MinFilter == GL_NEAREST_MIPMAP_NEAREST ||
677 samp->MinFilter == GL_NEAREST_MIPMAP_LINEAR)) {
678 minMagThresh = 0.5F;
679 }
680 else {
681 minMagThresh = 0.0F;
682 }
683
684 #if 0
685 /* DEBUG CODE: Verify that lambda[] is monotonic.
686 * We can't really use this because the inaccuracy in the LOG2 function
687 * causes this test to fail, yet the resulting texturing is correct.
688 */
689 if (n > 1) {
690 GLuint i;
691 printf("lambda delta = %g\n", lambda[0] - lambda[n-1]);
692 if (lambda[0] >= lambda[n-1]) { /* decreasing */
693 for (i = 0; i < n - 1; i++) {
694 assert((GLint) (lambda[i] * 10) >= (GLint) (lambda[i+1] * 10));
695 }
696 }
697 else { /* increasing */
698 for (i = 0; i < n - 1; i++) {
699 assert((GLint) (lambda[i] * 10) <= (GLint) (lambda[i+1] * 10));
700 }
701 }
702 }
703 #endif /* DEBUG */
704
705 if (lambda[0] <= minMagThresh && (n <= 1 || lambda[n-1] <= minMagThresh)) {
706 /* magnification for whole span */
707 *magStart = 0;
708 *magEnd = n;
709 *minStart = *minEnd = 0;
710 }
711 else if (lambda[0] > minMagThresh && (n <=1 || lambda[n-1] > minMagThresh)) {
712 /* minification for whole span */
713 *minStart = 0;
714 *minEnd = n;
715 *magStart = *magEnd = 0;
716 }
717 else {
718 /* a mix of minification and magnification */
719 GLuint i;
720 if (lambda[0] > minMagThresh) {
721 /* start with minification */
722 for (i = 1; i < n; i++) {
723 if (lambda[i] <= minMagThresh)
724 break;
725 }
726 *minStart = 0;
727 *minEnd = i;
728 *magStart = i;
729 *magEnd = n;
730 }
731 else {
732 /* start with magnification */
733 for (i = 1; i < n; i++) {
734 if (lambda[i] > minMagThresh)
735 break;
736 }
737 *magStart = 0;
738 *magEnd = i;
739 *minStart = i;
740 *minEnd = n;
741 }
742 }
743
744 #if 0
745 /* Verify the min/mag Start/End values
746 * We don't use this either (see above)
747 */
748 {
749 GLint i;
750 for (i = 0; i < n; i++) {
751 if (lambda[i] > minMagThresh) {
752 /* minification */
753 assert(i >= *minStart);
754 assert(i < *minEnd);
755 }
756 else {
757 /* magnification */
758 assert(i >= *magStart);
759 assert(i < *magEnd);
760 }
761 }
762 }
763 #endif
764 }
765
766
767 /**
768 * When we sample the border color, it must be interpreted according to
769 * the base texture format. Ex: if the texture base format it GL_ALPHA,
770 * we return (0,0,0,BorderAlpha).
771 */
772 static void
get_border_color(const struct gl_sampler_object * samp,const struct gl_texture_image * img,GLfloat rgba[4])773 get_border_color(const struct gl_sampler_object *samp,
774 const struct gl_texture_image *img,
775 GLfloat rgba[4])
776 {
777 switch (img->_BaseFormat) {
778 case GL_RGB:
779 rgba[0] = samp->BorderColor.f[0];
780 rgba[1] = samp->BorderColor.f[1];
781 rgba[2] = samp->BorderColor.f[2];
782 rgba[3] = 1.0F;
783 break;
784 case GL_ALPHA:
785 rgba[0] = rgba[1] = rgba[2] = 0.0;
786 rgba[3] = samp->BorderColor.f[3];
787 break;
788 case GL_LUMINANCE:
789 rgba[0] = rgba[1] = rgba[2] = samp->BorderColor.f[0];
790 rgba[3] = 1.0;
791 break;
792 case GL_LUMINANCE_ALPHA:
793 rgba[0] = rgba[1] = rgba[2] = samp->BorderColor.f[0];
794 rgba[3] = samp->BorderColor.f[3];
795 break;
796 case GL_INTENSITY:
797 rgba[0] = rgba[1] = rgba[2] = rgba[3] = samp->BorderColor.f[0];
798 break;
799 default:
800 COPY_4V(rgba, samp->BorderColor.f);
801 break;
802 }
803 }
804
805
806 /**
807 * Put z into texel according to GL_DEPTH_MODE.
808 */
809 static void
apply_depth_mode(GLenum depthMode,GLfloat z,GLfloat texel[4])810 apply_depth_mode(GLenum depthMode, GLfloat z, GLfloat texel[4])
811 {
812 switch (depthMode) {
813 case GL_LUMINANCE:
814 ASSIGN_4V(texel, z, z, z, 1.0F);
815 break;
816 case GL_INTENSITY:
817 ASSIGN_4V(texel, z, z, z, z);
818 break;
819 case GL_ALPHA:
820 ASSIGN_4V(texel, 0.0F, 0.0F, 0.0F, z);
821 break;
822 case GL_RED:
823 ASSIGN_4V(texel, z, 0.0F, 0.0F, 1.0F);
824 break;
825 default:
826 _mesa_problem(NULL, "Bad depth texture mode");
827 }
828 }
829
830
831 /**
832 * Is the given texture a depth (or depth/stencil) texture?
833 */
834 static GLboolean
is_depth_texture(const struct gl_texture_object * tObj)835 is_depth_texture(const struct gl_texture_object *tObj)
836 {
837 GLenum format = _mesa_texture_base_format(tObj);
838 return format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT;
839 }
840
841
842 /**********************************************************************/
843 /* 1-D Texture Sampling Functions */
844 /**********************************************************************/
845
846 /**
847 * Return the texture sample for coordinate (s) using GL_NEAREST filter.
848 */
849 static void
sample_1d_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[4])850 sample_1d_nearest(struct gl_context *ctx,
851 const struct gl_sampler_object *samp,
852 const struct gl_texture_image *img,
853 const GLfloat texcoord[4], GLfloat rgba[4])
854 {
855 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
856 const GLint width = img->Width2; /* without border, power of two */
857 GLint i;
858 i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
859 /* skip over the border, if any */
860 i += img->Border;
861 if (i < 0 || i >= (GLint) img->Width) {
862 /* Need this test for GL_CLAMP_TO_BORDER mode */
863 get_border_color(samp, img, rgba);
864 }
865 else {
866 swImg->FetchTexel(swImg, i, 0, 0, rgba);
867 }
868 }
869
870
871 /**
872 * Return the texture sample for coordinate (s) using GL_LINEAR filter.
873 */
874 static void
sample_1d_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[4])875 sample_1d_linear(struct gl_context *ctx,
876 const struct gl_sampler_object *samp,
877 const struct gl_texture_image *img,
878 const GLfloat texcoord[4], GLfloat rgba[4])
879 {
880 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
881 const GLint width = img->Width2;
882 GLint i0, i1;
883 GLbitfield useBorderColor = 0x0;
884 GLfloat a;
885 GLfloat t0[4], t1[4]; /* texels */
886
887 linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a);
888
889 if (img->Border) {
890 i0 += img->Border;
891 i1 += img->Border;
892 }
893 else {
894 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
895 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
896 }
897
898 /* fetch texel colors */
899 if (useBorderColor & I0BIT) {
900 get_border_color(samp, img, t0);
901 }
902 else {
903 swImg->FetchTexel(swImg, i0, 0, 0, t0);
904 }
905 if (useBorderColor & I1BIT) {
906 get_border_color(samp, img, t1);
907 }
908 else {
909 swImg->FetchTexel(swImg, i1, 0, 0, t1);
910 }
911
912 lerp_rgba(rgba, a, t0, t1);
913 }
914
915
916 static void
sample_1d_nearest_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])917 sample_1d_nearest_mipmap_nearest(struct gl_context *ctx,
918 const struct gl_sampler_object *samp,
919 const struct gl_texture_object *tObj,
920 GLuint n, const GLfloat texcoord[][4],
921 const GLfloat lambda[], GLfloat rgba[][4])
922 {
923 GLuint i;
924 assert(lambda != NULL);
925 for (i = 0; i < n; i++) {
926 GLint level = nearest_mipmap_level(tObj, lambda[i]);
927 sample_1d_nearest(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
928 }
929 }
930
931
932 static void
sample_1d_linear_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])933 sample_1d_linear_mipmap_nearest(struct gl_context *ctx,
934 const struct gl_sampler_object *samp,
935 const struct gl_texture_object *tObj,
936 GLuint n, const GLfloat texcoord[][4],
937 const GLfloat lambda[], GLfloat rgba[][4])
938 {
939 GLuint i;
940 assert(lambda != NULL);
941 for (i = 0; i < n; i++) {
942 GLint level = nearest_mipmap_level(tObj, lambda[i]);
943 sample_1d_linear(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
944 }
945 }
946
947
948 static void
sample_1d_nearest_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])949 sample_1d_nearest_mipmap_linear(struct gl_context *ctx,
950 const struct gl_sampler_object *samp,
951 const struct gl_texture_object *tObj,
952 GLuint n, const GLfloat texcoord[][4],
953 const GLfloat lambda[], GLfloat rgba[][4])
954 {
955 GLuint i;
956 assert(lambda != NULL);
957 for (i = 0; i < n; i++) {
958 GLint level = linear_mipmap_level(tObj, lambda[i]);
959 if (level >= tObj->_MaxLevel) {
960 sample_1d_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
961 texcoord[i], rgba[i]);
962 }
963 else {
964 GLfloat t0[4], t1[4];
965 const GLfloat f = FRAC(lambda[i]);
966 sample_1d_nearest(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
967 sample_1d_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
968 lerp_rgba(rgba[i], f, t0, t1);
969 }
970 }
971 }
972
973
974 static void
sample_1d_linear_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])975 sample_1d_linear_mipmap_linear(struct gl_context *ctx,
976 const struct gl_sampler_object *samp,
977 const struct gl_texture_object *tObj,
978 GLuint n, const GLfloat texcoord[][4],
979 const GLfloat lambda[], GLfloat rgba[][4])
980 {
981 GLuint i;
982 assert(lambda != NULL);
983 for (i = 0; i < n; i++) {
984 GLint level = linear_mipmap_level(tObj, lambda[i]);
985 if (level >= tObj->_MaxLevel) {
986 sample_1d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
987 texcoord[i], rgba[i]);
988 }
989 else {
990 GLfloat t0[4], t1[4];
991 const GLfloat f = FRAC(lambda[i]);
992 sample_1d_linear(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
993 sample_1d_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
994 lerp_rgba(rgba[i], f, t0, t1);
995 }
996 }
997 }
998
999
1000 /** Sample 1D texture, nearest filtering for both min/magnification */
1001 static void
sample_nearest_1d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])1002 sample_nearest_1d( struct gl_context *ctx,
1003 const struct gl_sampler_object *samp,
1004 const struct gl_texture_object *tObj, GLuint n,
1005 const GLfloat texcoords[][4], const GLfloat lambda[],
1006 GLfloat rgba[][4] )
1007 {
1008 GLuint i;
1009 const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
1010 (void) lambda;
1011 for (i = 0; i < n; i++) {
1012 sample_1d_nearest(ctx, samp, image, texcoords[i], rgba[i]);
1013 }
1014 }
1015
1016
1017 /** Sample 1D texture, linear filtering for both min/magnification */
1018 static void
sample_linear_1d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])1019 sample_linear_1d( struct gl_context *ctx,
1020 const struct gl_sampler_object *samp,
1021 const struct gl_texture_object *tObj, GLuint n,
1022 const GLfloat texcoords[][4], const GLfloat lambda[],
1023 GLfloat rgba[][4] )
1024 {
1025 GLuint i;
1026 const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
1027 (void) lambda;
1028 for (i = 0; i < n; i++) {
1029 sample_1d_linear(ctx, samp, image, texcoords[i], rgba[i]);
1030 }
1031 }
1032
1033
1034 /** Sample 1D texture, using lambda to choose between min/magnification */
1035 static void
sample_lambda_1d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])1036 sample_lambda_1d( struct gl_context *ctx,
1037 const struct gl_sampler_object *samp,
1038 const struct gl_texture_object *tObj, GLuint n,
1039 const GLfloat texcoords[][4],
1040 const GLfloat lambda[], GLfloat rgba[][4] )
1041 {
1042 GLuint minStart, minEnd; /* texels with minification */
1043 GLuint magStart, magEnd; /* texels with magnification */
1044 GLuint i;
1045
1046 assert(lambda != NULL);
1047 compute_min_mag_ranges(samp, n, lambda,
1048 &minStart, &minEnd, &magStart, &magEnd);
1049
1050 if (minStart < minEnd) {
1051 /* do the minified texels */
1052 const GLuint m = minEnd - minStart;
1053 switch (samp->MinFilter) {
1054 case GL_NEAREST:
1055 for (i = minStart; i < minEnd; i++)
1056 sample_1d_nearest(ctx, samp, _mesa_base_tex_image(tObj),
1057 texcoords[i], rgba[i]);
1058 break;
1059 case GL_LINEAR:
1060 for (i = minStart; i < minEnd; i++)
1061 sample_1d_linear(ctx, samp, _mesa_base_tex_image(tObj),
1062 texcoords[i], rgba[i]);
1063 break;
1064 case GL_NEAREST_MIPMAP_NEAREST:
1065 sample_1d_nearest_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
1066 lambda + minStart, rgba + minStart);
1067 break;
1068 case GL_LINEAR_MIPMAP_NEAREST:
1069 sample_1d_linear_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
1070 lambda + minStart, rgba + minStart);
1071 break;
1072 case GL_NEAREST_MIPMAP_LINEAR:
1073 sample_1d_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
1074 lambda + minStart, rgba + minStart);
1075 break;
1076 case GL_LINEAR_MIPMAP_LINEAR:
1077 sample_1d_linear_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
1078 lambda + minStart, rgba + minStart);
1079 break;
1080 default:
1081 _mesa_problem(ctx, "Bad min filter in sample_1d_texture");
1082 return;
1083 }
1084 }
1085
1086 if (magStart < magEnd) {
1087 /* do the magnified texels */
1088 switch (samp->MagFilter) {
1089 case GL_NEAREST:
1090 for (i = magStart; i < magEnd; i++)
1091 sample_1d_nearest(ctx, samp, _mesa_base_tex_image(tObj),
1092 texcoords[i], rgba[i]);
1093 break;
1094 case GL_LINEAR:
1095 for (i = magStart; i < magEnd; i++)
1096 sample_1d_linear(ctx, samp, _mesa_base_tex_image(tObj),
1097 texcoords[i], rgba[i]);
1098 break;
1099 default:
1100 _mesa_problem(ctx, "Bad mag filter in sample_1d_texture");
1101 return;
1102 }
1103 }
1104 }
1105
1106
1107 /**********************************************************************/
1108 /* 2-D Texture Sampling Functions */
1109 /**********************************************************************/
1110
1111
1112 /**
1113 * Return the texture sample for coordinate (s,t) using GL_NEAREST filter.
1114 */
1115 static void
sample_2d_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[])1116 sample_2d_nearest(struct gl_context *ctx,
1117 const struct gl_sampler_object *samp,
1118 const struct gl_texture_image *img,
1119 const GLfloat texcoord[4],
1120 GLfloat rgba[])
1121 {
1122 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1123 const GLint width = img->Width2; /* without border, power of two */
1124 const GLint height = img->Height2; /* without border, power of two */
1125 GLint i, j;
1126 (void) ctx;
1127
1128 i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
1129 j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
1130
1131 /* skip over the border, if any */
1132 i += img->Border;
1133 j += img->Border;
1134
1135 if (i < 0 || i >= (GLint) img->Width || j < 0 || j >= (GLint) img->Height) {
1136 /* Need this test for GL_CLAMP_TO_BORDER mode */
1137 get_border_color(samp, img, rgba);
1138 }
1139 else {
1140 swImg->FetchTexel(swImg, i, j, 0, rgba);
1141 }
1142 }
1143
1144
1145 /**
1146 * Return the texture sample for coordinate (s,t) using GL_LINEAR filter.
1147 * New sampling code contributed by Lynn Quam <quam@ai.sri.com>.
1148 */
1149 static void
sample_2d_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[])1150 sample_2d_linear(struct gl_context *ctx,
1151 const struct gl_sampler_object *samp,
1152 const struct gl_texture_image *img,
1153 const GLfloat texcoord[4],
1154 GLfloat rgba[])
1155 {
1156 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1157 const GLint width = img->Width2;
1158 const GLint height = img->Height2;
1159 GLint i0, j0, i1, j1;
1160 GLbitfield useBorderColor = 0x0;
1161 GLfloat a, b;
1162 GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */
1163
1164 linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a);
1165 linear_texel_locations(samp->WrapT, img, height, texcoord[1], &j0, &j1, &b);
1166
1167 if (img->Border) {
1168 i0 += img->Border;
1169 i1 += img->Border;
1170 j0 += img->Border;
1171 j1 += img->Border;
1172 }
1173 else {
1174 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
1175 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
1176 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
1177 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
1178 }
1179
1180 /* fetch four texel colors */
1181 if (useBorderColor & (I0BIT | J0BIT)) {
1182 get_border_color(samp, img, t00);
1183 }
1184 else {
1185 swImg->FetchTexel(swImg, i0, j0, 0, t00);
1186 }
1187 if (useBorderColor & (I1BIT | J0BIT)) {
1188 get_border_color(samp, img, t10);
1189 }
1190 else {
1191 swImg->FetchTexel(swImg, i1, j0, 0, t10);
1192 }
1193 if (useBorderColor & (I0BIT | J1BIT)) {
1194 get_border_color(samp, img, t01);
1195 }
1196 else {
1197 swImg->FetchTexel(swImg, i0, j1, 0, t01);
1198 }
1199 if (useBorderColor & (I1BIT | J1BIT)) {
1200 get_border_color(samp, img, t11);
1201 }
1202 else {
1203 swImg->FetchTexel(swImg, i1, j1, 0, t11);
1204 }
1205
1206 lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11);
1207 }
1208
1209
1210 /**
1211 * As above, but we know WRAP_S == REPEAT and WRAP_T == REPEAT.
1212 * We don't have to worry about the texture border.
1213 */
1214 static void
sample_2d_linear_repeat(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[])1215 sample_2d_linear_repeat(struct gl_context *ctx,
1216 const struct gl_sampler_object *samp,
1217 const struct gl_texture_image *img,
1218 const GLfloat texcoord[4],
1219 GLfloat rgba[])
1220 {
1221 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1222 const GLint width = img->Width2;
1223 const GLint height = img->Height2;
1224 GLint i0, j0, i1, j1;
1225 GLfloat wi, wj;
1226 GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */
1227
1228 (void) ctx;
1229
1230 assert(samp->WrapS == GL_REPEAT);
1231 assert(samp->WrapT == GL_REPEAT);
1232 assert(img->Border == 0);
1233 assert(swImg->_IsPowerOfTwo);
1234
1235 linear_repeat_texel_location(width, texcoord[0], &i0, &i1, &wi);
1236 linear_repeat_texel_location(height, texcoord[1], &j0, &j1, &wj);
1237
1238 swImg->FetchTexel(swImg, i0, j0, 0, t00);
1239 swImg->FetchTexel(swImg, i1, j0, 0, t10);
1240 swImg->FetchTexel(swImg, i0, j1, 0, t01);
1241 swImg->FetchTexel(swImg, i1, j1, 0, t11);
1242
1243 lerp_rgba_2d(rgba, wi, wj, t00, t10, t01, t11);
1244 }
1245
1246
1247 static void
sample_2d_nearest_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])1248 sample_2d_nearest_mipmap_nearest(struct gl_context *ctx,
1249 const struct gl_sampler_object *samp,
1250 const struct gl_texture_object *tObj,
1251 GLuint n, const GLfloat texcoord[][4],
1252 const GLfloat lambda[], GLfloat rgba[][4])
1253 {
1254 GLuint i;
1255 for (i = 0; i < n; i++) {
1256 GLint level = nearest_mipmap_level(tObj, lambda[i]);
1257 sample_2d_nearest(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
1258 }
1259 }
1260
1261
1262 static void
sample_2d_linear_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])1263 sample_2d_linear_mipmap_nearest(struct gl_context *ctx,
1264 const struct gl_sampler_object *samp,
1265 const struct gl_texture_object *tObj,
1266 GLuint n, const GLfloat texcoord[][4],
1267 const GLfloat lambda[], GLfloat rgba[][4])
1268 {
1269 GLuint i;
1270 assert(lambda != NULL);
1271 for (i = 0; i < n; i++) {
1272 GLint level = nearest_mipmap_level(tObj, lambda[i]);
1273 sample_2d_linear(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
1274 }
1275 }
1276
1277
1278 static void
sample_2d_nearest_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])1279 sample_2d_nearest_mipmap_linear(struct gl_context *ctx,
1280 const struct gl_sampler_object *samp,
1281 const struct gl_texture_object *tObj,
1282 GLuint n, const GLfloat texcoord[][4],
1283 const GLfloat lambda[], GLfloat rgba[][4])
1284 {
1285 GLuint i;
1286 assert(lambda != NULL);
1287 for (i = 0; i < n; i++) {
1288 GLint level = linear_mipmap_level(tObj, lambda[i]);
1289 if (level >= tObj->_MaxLevel) {
1290 sample_2d_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
1291 texcoord[i], rgba[i]);
1292 }
1293 else {
1294 GLfloat t0[4], t1[4]; /* texels */
1295 const GLfloat f = FRAC(lambda[i]);
1296 sample_2d_nearest(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
1297 sample_2d_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
1298 lerp_rgba(rgba[i], f, t0, t1);
1299 }
1300 }
1301 }
1302
1303
1304 static void
sample_2d_linear_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])1305 sample_2d_linear_mipmap_linear( struct gl_context *ctx,
1306 const struct gl_sampler_object *samp,
1307 const struct gl_texture_object *tObj,
1308 GLuint n, const GLfloat texcoord[][4],
1309 const GLfloat lambda[], GLfloat rgba[][4] )
1310 {
1311 GLuint i;
1312 assert(lambda != NULL);
1313 for (i = 0; i < n; i++) {
1314 GLint level = linear_mipmap_level(tObj, lambda[i]);
1315 if (level >= tObj->_MaxLevel) {
1316 sample_2d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
1317 texcoord[i], rgba[i]);
1318 }
1319 else {
1320 GLfloat t0[4], t1[4]; /* texels */
1321 const GLfloat f = FRAC(lambda[i]);
1322 sample_2d_linear(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
1323 sample_2d_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
1324 lerp_rgba(rgba[i], f, t0, t1);
1325 }
1326 }
1327 }
1328
1329
1330 static void
sample_2d_linear_mipmap_linear_repeat(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])1331 sample_2d_linear_mipmap_linear_repeat(struct gl_context *ctx,
1332 const struct gl_sampler_object *samp,
1333 const struct gl_texture_object *tObj,
1334 GLuint n, const GLfloat texcoord[][4],
1335 const GLfloat lambda[], GLfloat rgba[][4])
1336 {
1337 GLuint i;
1338 assert(lambda != NULL);
1339 assert(samp->WrapS == GL_REPEAT);
1340 assert(samp->WrapT == GL_REPEAT);
1341 for (i = 0; i < n; i++) {
1342 GLint level = linear_mipmap_level(tObj, lambda[i]);
1343 if (level >= tObj->_MaxLevel) {
1344 sample_2d_linear_repeat(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
1345 texcoord[i], rgba[i]);
1346 }
1347 else {
1348 GLfloat t0[4], t1[4]; /* texels */
1349 const GLfloat f = FRAC(lambda[i]);
1350 sample_2d_linear_repeat(ctx, samp, tObj->Image[0][level ],
1351 texcoord[i], t0);
1352 sample_2d_linear_repeat(ctx, samp, tObj->Image[0][level+1],
1353 texcoord[i], t1);
1354 lerp_rgba(rgba[i], f, t0, t1);
1355 }
1356 }
1357 }
1358
1359
1360 /** Sample 2D texture, nearest filtering for both min/magnification */
1361 static void
sample_nearest_2d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])1362 sample_nearest_2d(struct gl_context *ctx,
1363 const struct gl_sampler_object *samp,
1364 const struct gl_texture_object *tObj, GLuint n,
1365 const GLfloat texcoords[][4],
1366 const GLfloat lambda[], GLfloat rgba[][4])
1367 {
1368 GLuint i;
1369 const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
1370 (void) lambda;
1371 for (i = 0; i < n; i++) {
1372 sample_2d_nearest(ctx, samp, image, texcoords[i], rgba[i]);
1373 }
1374 }
1375
1376
1377 /** Sample 2D texture, linear filtering for both min/magnification */
1378 static void
sample_linear_2d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])1379 sample_linear_2d(struct gl_context *ctx,
1380 const struct gl_sampler_object *samp,
1381 const struct gl_texture_object *tObj, GLuint n,
1382 const GLfloat texcoords[][4],
1383 const GLfloat lambda[], GLfloat rgba[][4])
1384 {
1385 GLuint i;
1386 const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
1387 const struct swrast_texture_image *swImg = swrast_texture_image_const(image);
1388 (void) lambda;
1389 if (samp->WrapS == GL_REPEAT &&
1390 samp->WrapT == GL_REPEAT &&
1391 swImg->_IsPowerOfTwo &&
1392 image->Border == 0) {
1393 for (i = 0; i < n; i++) {
1394 sample_2d_linear_repeat(ctx, samp, image, texcoords[i], rgba[i]);
1395 }
1396 }
1397 else {
1398 for (i = 0; i < n; i++) {
1399 sample_2d_linear(ctx, samp, image, texcoords[i], rgba[i]);
1400 }
1401 }
1402 }
1403
1404
1405 /**
1406 * Optimized 2-D texture sampling:
1407 * S and T wrap mode == GL_REPEAT
1408 * GL_NEAREST min/mag filter
1409 * No border,
1410 * RowStride == Width,
1411 * Format = GL_RGB
1412 */
1413 static void
opt_sample_rgb_2d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])1414 opt_sample_rgb_2d(struct gl_context *ctx,
1415 const struct gl_sampler_object *samp,
1416 const struct gl_texture_object *tObj,
1417 GLuint n, const GLfloat texcoords[][4],
1418 const GLfloat lambda[], GLfloat rgba[][4])
1419 {
1420 const struct gl_texture_image *img = _mesa_base_tex_image(tObj);
1421 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1422 const GLfloat width = (GLfloat) img->Width;
1423 const GLfloat height = (GLfloat) img->Height;
1424 const GLint colMask = img->Width - 1;
1425 const GLint rowMask = img->Height - 1;
1426 const GLint shift = img->WidthLog2;
1427 GLuint k;
1428 (void) ctx;
1429 (void) lambda;
1430 assert(samp->WrapS==GL_REPEAT);
1431 assert(samp->WrapT==GL_REPEAT);
1432 assert(img->Border==0);
1433 assert(img->TexFormat == MESA_FORMAT_BGR_UNORM8);
1434 assert(swImg->_IsPowerOfTwo);
1435 (void) swImg;
1436
1437 for (k=0; k<n; k++) {
1438 GLint i = util_ifloor(texcoords[k][0] * width) & colMask;
1439 GLint j = util_ifloor(texcoords[k][1] * height) & rowMask;
1440 GLint pos = (j << shift) | i;
1441 GLubyte *texel = (GLubyte *) swImg->ImageSlices[0] + 3 * pos;
1442 rgba[k][RCOMP] = UBYTE_TO_FLOAT(texel[2]);
1443 rgba[k][GCOMP] = UBYTE_TO_FLOAT(texel[1]);
1444 rgba[k][BCOMP] = UBYTE_TO_FLOAT(texel[0]);
1445 rgba[k][ACOMP] = 1.0F;
1446 }
1447 }
1448
1449
1450 /**
1451 * Optimized 2-D texture sampling:
1452 * S and T wrap mode == GL_REPEAT
1453 * GL_NEAREST min/mag filter
1454 * No border
1455 * RowStride == Width,
1456 * Format = GL_RGBA
1457 */
1458 static void
opt_sample_rgba_2d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])1459 opt_sample_rgba_2d(struct gl_context *ctx,
1460 const struct gl_sampler_object *samp,
1461 const struct gl_texture_object *tObj,
1462 GLuint n, const GLfloat texcoords[][4],
1463 const GLfloat lambda[], GLfloat rgba[][4])
1464 {
1465 const struct gl_texture_image *img = _mesa_base_tex_image(tObj);
1466 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
1467 const GLfloat width = (GLfloat) img->Width;
1468 const GLfloat height = (GLfloat) img->Height;
1469 const GLint colMask = img->Width - 1;
1470 const GLint rowMask = img->Height - 1;
1471 const GLint shift = img->WidthLog2;
1472 GLuint i;
1473 (void) ctx;
1474 (void) lambda;
1475 assert(samp->WrapS==GL_REPEAT);
1476 assert(samp->WrapT==GL_REPEAT);
1477 assert(img->Border==0);
1478 assert(img->TexFormat == MESA_FORMAT_A8B8G8R8_UNORM);
1479 assert(swImg->_IsPowerOfTwo);
1480 (void) swImg;
1481
1482 for (i = 0; i < n; i++) {
1483 const GLint col = util_ifloor(texcoords[i][0] * width) & colMask;
1484 const GLint row = util_ifloor(texcoords[i][1] * height) & rowMask;
1485 const GLint pos = (row << shift) | col;
1486 const GLuint texel = *((GLuint *) swImg->ImageSlices[0] + pos);
1487 rgba[i][RCOMP] = UBYTE_TO_FLOAT( (texel >> 24) );
1488 rgba[i][GCOMP] = UBYTE_TO_FLOAT( (texel >> 16) & 0xff );
1489 rgba[i][BCOMP] = UBYTE_TO_FLOAT( (texel >> 8) & 0xff );
1490 rgba[i][ACOMP] = UBYTE_TO_FLOAT( (texel ) & 0xff );
1491 }
1492 }
1493
1494
1495 /** Sample 2D texture, using lambda to choose between min/magnification */
1496 static void
sample_lambda_2d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])1497 sample_lambda_2d(struct gl_context *ctx,
1498 const struct gl_sampler_object *samp,
1499 const struct gl_texture_object *tObj,
1500 GLuint n, const GLfloat texcoords[][4],
1501 const GLfloat lambda[], GLfloat rgba[][4])
1502 {
1503 const struct gl_texture_image *tImg = _mesa_base_tex_image(tObj);
1504 const struct swrast_texture_image *swImg = swrast_texture_image_const(tImg);
1505 GLuint minStart, minEnd; /* texels with minification */
1506 GLuint magStart, magEnd; /* texels with magnification */
1507
1508 const GLboolean repeatNoBorderPOT = (samp->WrapS == GL_REPEAT)
1509 && (samp->WrapT == GL_REPEAT)
1510 && (tImg->Border == 0)
1511 && (_mesa_format_row_stride(tImg->TexFormat, tImg->Width) ==
1512 swImg->RowStride)
1513 && swImg->_IsPowerOfTwo;
1514
1515 assert(lambda != NULL);
1516 compute_min_mag_ranges(samp, n, lambda,
1517 &minStart, &minEnd, &magStart, &magEnd);
1518
1519 if (minStart < minEnd) {
1520 /* do the minified texels */
1521 const GLuint m = minEnd - minStart;
1522 switch (samp->MinFilter) {
1523 case GL_NEAREST:
1524 if (repeatNoBorderPOT) {
1525 switch (tImg->TexFormat) {
1526 case MESA_FORMAT_BGR_UNORM8:
1527 opt_sample_rgb_2d(ctx, samp, tObj, m, texcoords + minStart,
1528 NULL, rgba + minStart);
1529 break;
1530 case MESA_FORMAT_A8B8G8R8_UNORM:
1531 opt_sample_rgba_2d(ctx, samp, tObj, m, texcoords + minStart,
1532 NULL, rgba + minStart);
1533 break;
1534 default:
1535 sample_nearest_2d(ctx, samp, tObj, m, texcoords + minStart,
1536 NULL, rgba + minStart );
1537 }
1538 }
1539 else {
1540 sample_nearest_2d(ctx, samp, tObj, m, texcoords + minStart,
1541 NULL, rgba + minStart);
1542 }
1543 break;
1544 case GL_LINEAR:
1545 sample_linear_2d(ctx, samp, tObj, m, texcoords + minStart,
1546 NULL, rgba + minStart);
1547 break;
1548 case GL_NEAREST_MIPMAP_NEAREST:
1549 sample_2d_nearest_mipmap_nearest(ctx, samp, tObj, m,
1550 texcoords + minStart,
1551 lambda + minStart, rgba + minStart);
1552 break;
1553 case GL_LINEAR_MIPMAP_NEAREST:
1554 sample_2d_linear_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
1555 lambda + minStart, rgba + minStart);
1556 break;
1557 case GL_NEAREST_MIPMAP_LINEAR:
1558 sample_2d_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
1559 lambda + minStart, rgba + minStart);
1560 break;
1561 case GL_LINEAR_MIPMAP_LINEAR:
1562 if (repeatNoBorderPOT)
1563 sample_2d_linear_mipmap_linear_repeat(ctx, samp, tObj, m,
1564 texcoords + minStart, lambda + minStart, rgba + minStart);
1565 else
1566 sample_2d_linear_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
1567 lambda + minStart, rgba + minStart);
1568 break;
1569 default:
1570 _mesa_problem(ctx, "Bad min filter in sample_2d_texture");
1571 return;
1572 }
1573 }
1574
1575 if (magStart < magEnd) {
1576 /* do the magnified texels */
1577 const GLuint m = magEnd - magStart;
1578
1579 switch (samp->MagFilter) {
1580 case GL_NEAREST:
1581 if (repeatNoBorderPOT) {
1582 switch (tImg->TexFormat) {
1583 case MESA_FORMAT_BGR_UNORM8:
1584 opt_sample_rgb_2d(ctx, samp, tObj, m, texcoords + magStart,
1585 NULL, rgba + magStart);
1586 break;
1587 case MESA_FORMAT_A8B8G8R8_UNORM:
1588 opt_sample_rgba_2d(ctx, samp, tObj, m, texcoords + magStart,
1589 NULL, rgba + magStart);
1590 break;
1591 default:
1592 sample_nearest_2d(ctx, samp, tObj, m, texcoords + magStart,
1593 NULL, rgba + magStart );
1594 }
1595 }
1596 else {
1597 sample_nearest_2d(ctx, samp, tObj, m, texcoords + magStart,
1598 NULL, rgba + magStart);
1599 }
1600 break;
1601 case GL_LINEAR:
1602 sample_linear_2d(ctx, samp, tObj, m, texcoords + magStart,
1603 NULL, rgba + magStart);
1604 break;
1605 default:
1606 _mesa_problem(ctx, "Bad mag filter in sample_lambda_2d");
1607 break;
1608 }
1609 }
1610 }
1611
1612
1613 /* For anisotropic filtering */
1614 #define WEIGHT_LUT_SIZE 1024
1615
1616 static GLfloat *weightLut = NULL;
1617
1618 /**
1619 * Creates the look-up table used to speed-up EWA sampling
1620 */
1621 static void
create_filter_table(void)1622 create_filter_table(void)
1623 {
1624 GLuint i;
1625 if (!weightLut) {
1626 weightLut = malloc(WEIGHT_LUT_SIZE * sizeof(GLfloat));
1627
1628 for (i = 0; i < WEIGHT_LUT_SIZE; ++i) {
1629 GLfloat alpha = 2;
1630 GLfloat r2 = (GLfloat) i / (GLfloat) (WEIGHT_LUT_SIZE - 1);
1631 GLfloat weight = expf(-alpha * r2);
1632 weightLut[i] = weight;
1633 }
1634 }
1635 }
1636
1637
1638 /**
1639 * Elliptical weighted average (EWA) filter for producing high quality
1640 * anisotropic filtered results.
1641 * Based on the Higher Quality Elliptical Weighted Avarage Filter
1642 * published by Paul S. Heckbert in his Master's Thesis
1643 * "Fundamentals of Texture Mapping and Image Warping" (1989)
1644 */
1645 static void
sample_2d_ewa(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,const GLfloat texcoord[4],const GLfloat dudx,const GLfloat dvdx,const GLfloat dudy,const GLfloat dvdy,const GLint lod,GLfloat rgba[])1646 sample_2d_ewa(struct gl_context *ctx,
1647 const struct gl_sampler_object *samp,
1648 const struct gl_texture_object *tObj,
1649 const GLfloat texcoord[4],
1650 const GLfloat dudx, const GLfloat dvdx,
1651 const GLfloat dudy, const GLfloat dvdy, const GLint lod,
1652 GLfloat rgba[])
1653 {
1654 GLint level = lod > 0 ? lod : 0;
1655 GLfloat scaling = 1.0f / (1 << level);
1656 const struct gl_texture_image *img = tObj->Image[0][level];
1657 const struct gl_texture_image *mostDetailedImage =
1658 _mesa_base_tex_image(tObj);
1659 const struct swrast_texture_image *swImg =
1660 swrast_texture_image_const(mostDetailedImage);
1661 GLfloat tex_u = -0.5f + texcoord[0] * swImg->WidthScale * scaling;
1662 GLfloat tex_v = -0.5f + texcoord[1] * swImg->HeightScale * scaling;
1663
1664 GLfloat ux = dudx * scaling;
1665 GLfloat vx = dvdx * scaling;
1666 GLfloat uy = dudy * scaling;
1667 GLfloat vy = dvdy * scaling;
1668
1669 /* compute ellipse coefficients to bound the region:
1670 * A*x*x + B*x*y + C*y*y = F.
1671 */
1672 GLfloat A = vx*vx+vy*vy+1;
1673 GLfloat B = -2*(ux*vx+uy*vy);
1674 GLfloat C = ux*ux+uy*uy+1;
1675 GLfloat F = A*C-B*B/4.0f;
1676
1677 /* check if it is an ellipse */
1678 /* assert(F > 0.0); */
1679
1680 /* Compute the ellipse's (u,v) bounding box in texture space */
1681 GLfloat d = -B*B+4.0f*C*A;
1682 GLfloat box_u = 2.0f / d * sqrtf(d*C*F); /* box_u -> half of bbox with */
1683 GLfloat box_v = 2.0f / d * sqrtf(A*d*F); /* box_v -> half of bbox height */
1684
1685 GLint u0 = (GLint) floorf(tex_u - box_u);
1686 GLint u1 = (GLint) ceilf (tex_u + box_u);
1687 GLint v0 = (GLint) floorf(tex_v - box_v);
1688 GLint v1 = (GLint) ceilf (tex_v + box_v);
1689
1690 GLfloat num[4] = {0.0F, 0.0F, 0.0F, 0.0F};
1691 GLfloat newCoord[2];
1692 GLfloat den = 0.0F;
1693 GLfloat ddq;
1694 GLfloat U = u0 - tex_u;
1695 GLint v;
1696
1697 /* Scale ellipse formula to directly index the Filter Lookup Table.
1698 * i.e. scale so that F = WEIGHT_LUT_SIZE-1
1699 */
1700 GLfloat formScale = (GLfloat) (WEIGHT_LUT_SIZE - 1) / F;
1701 A *= formScale;
1702 B *= formScale;
1703 C *= formScale;
1704 /* F *= formScale; */ /* no need to scale F as we don't use it below here */
1705
1706 /* Heckbert MS thesis, p. 59; scan over the bounding box of the ellipse
1707 * and incrementally update the value of Ax^2+Bxy*Cy^2; when this
1708 * value, q, is less than F, we're inside the ellipse
1709 */
1710 ddq = 2 * A;
1711 for (v = v0; v <= v1; ++v) {
1712 GLfloat V = v - tex_v;
1713 GLfloat dq = A * (2 * U + 1) + B * V;
1714 GLfloat q = (C * V + B * U) * V + A * U * U;
1715
1716 GLint u;
1717 for (u = u0; u <= u1; ++u) {
1718 /* Note that the ellipse has been pre-scaled so F = WEIGHT_LUT_SIZE - 1 */
1719 if (q < WEIGHT_LUT_SIZE) {
1720 /* as a LUT is used, q must never be negative;
1721 * should not happen, though
1722 */
1723 const GLint qClamped = q >= 0.0F ? (GLint) q : 0;
1724 GLfloat weight = weightLut[qClamped];
1725
1726 newCoord[0] = u / ((GLfloat) img->Width2);
1727 newCoord[1] = v / ((GLfloat) img->Height2);
1728
1729 sample_2d_nearest(ctx, samp, img, newCoord, rgba);
1730 num[0] += weight * rgba[0];
1731 num[1] += weight * rgba[1];
1732 num[2] += weight * rgba[2];
1733 num[3] += weight * rgba[3];
1734
1735 den += weight;
1736 }
1737 q += dq;
1738 dq += ddq;
1739 }
1740 }
1741
1742 if (den <= 0.0F) {
1743 /* Reaching this place would mean
1744 * that no pixels intersected the ellipse.
1745 * This should never happen because
1746 * the filter we use always
1747 * intersects at least one pixel.
1748 */
1749
1750 /*rgba[0]=0;
1751 rgba[1]=0;
1752 rgba[2]=0;
1753 rgba[3]=0;*/
1754 /* not enough pixels in resampling, resort to direct interpolation */
1755 sample_2d_linear(ctx, samp, img, texcoord, rgba);
1756 return;
1757 }
1758
1759 rgba[0] = num[0] / den;
1760 rgba[1] = num[1] / den;
1761 rgba[2] = num[2] / den;
1762 rgba[3] = num[3] / den;
1763 }
1764
1765
1766 /**
1767 * Anisotropic filtering using footprint assembly as outlined in the
1768 * EXT_texture_filter_anisotropic spec:
1769 * http://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt
1770 * Faster than EWA but has less quality (more aliasing effects)
1771 */
1772 static void
sample_2d_footprint(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,const GLfloat texcoord[4],const GLfloat dudx,const GLfloat dvdx,const GLfloat dudy,const GLfloat dvdy,const GLint lod,GLfloat rgba[])1773 sample_2d_footprint(struct gl_context *ctx,
1774 const struct gl_sampler_object *samp,
1775 const struct gl_texture_object *tObj,
1776 const GLfloat texcoord[4],
1777 const GLfloat dudx, const GLfloat dvdx,
1778 const GLfloat dudy, const GLfloat dvdy, const GLint lod,
1779 GLfloat rgba[])
1780 {
1781 GLint level = lod > 0 ? lod : 0;
1782 GLfloat scaling = 1.0F / (1 << level);
1783 const struct gl_texture_image *img = tObj->Image[0][level];
1784
1785 GLfloat ux = dudx * scaling;
1786 GLfloat vx = dvdx * scaling;
1787 GLfloat uy = dudy * scaling;
1788 GLfloat vy = dvdy * scaling;
1789
1790 GLfloat Px2 = ux * ux + vx * vx; /* squared length of dx */
1791 GLfloat Py2 = uy * uy + vy * vy; /* squared length of dy */
1792
1793 GLint numSamples;
1794 GLfloat ds;
1795 GLfloat dt;
1796
1797 GLfloat num[4] = {0.0F, 0.0F, 0.0F, 0.0F};
1798 GLfloat newCoord[2];
1799 GLint s;
1800
1801 /* Calculate the per anisotropic sample offsets in s,t space. */
1802 if (Px2 > Py2) {
1803 numSamples = (GLint) ceilf(sqrtf(Px2));
1804 ds = ux / ((GLfloat) img->Width2);
1805 dt = vx / ((GLfloat) img->Height2);
1806 }
1807 else {
1808 numSamples = (GLint) ceilf(sqrtf(Py2));
1809 ds = uy / ((GLfloat) img->Width2);
1810 dt = vy / ((GLfloat) img->Height2);
1811 }
1812
1813 for (s = 0; s<numSamples; s++) {
1814 newCoord[0] = texcoord[0] + ds * ((GLfloat)(s+1) / (numSamples+1) -0.5f);
1815 newCoord[1] = texcoord[1] + dt * ((GLfloat)(s+1) / (numSamples+1) -0.5f);
1816
1817 sample_2d_linear(ctx, samp, img, newCoord, rgba);
1818 num[0] += rgba[0];
1819 num[1] += rgba[1];
1820 num[2] += rgba[2];
1821 num[3] += rgba[3];
1822 }
1823
1824 rgba[0] = num[0] / numSamples;
1825 rgba[1] = num[1] / numSamples;
1826 rgba[2] = num[2] / numSamples;
1827 rgba[3] = num[3] / numSamples;
1828 }
1829
1830
1831 /**
1832 * Returns the index of the specified texture object in the
1833 * gl_context texture unit array.
1834 */
1835 static GLuint
texture_unit_index(const struct gl_context * ctx,const struct gl_texture_object * tObj)1836 texture_unit_index(const struct gl_context *ctx,
1837 const struct gl_texture_object *tObj)
1838 {
1839 const GLuint maxUnit
1840 = (ctx->Texture._EnabledCoordUnits > 1) ? ctx->Const.MaxTextureUnits : 1;
1841 GLuint u;
1842
1843 /* XXX CoordUnits vs. ImageUnits */
1844 for (u = 0; u < maxUnit; u++) {
1845 if (ctx->Texture.Unit[u]._Current == tObj)
1846 break; /* found */
1847 }
1848 if (u >= maxUnit)
1849 u = 0; /* not found, use 1st one; should never happen */
1850
1851 return u;
1852 }
1853
1854
1855 /**
1856 * Sample 2D texture using an anisotropic filter.
1857 * NOTE: the const GLfloat lambda_iso[] parameter does *NOT* contain
1858 * the lambda float array but a "hidden" SWspan struct which is required
1859 * by this function but is not available in the texture_sample_func signature.
1860 * See _swrast_texture_span( struct gl_context *ctx, SWspan *span ) on how
1861 * this function is called.
1862 */
1863 static void
sample_lambda_2d_aniso(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda_iso[],GLfloat rgba[][4])1864 sample_lambda_2d_aniso(struct gl_context *ctx,
1865 const struct gl_sampler_object *samp,
1866 const struct gl_texture_object *tObj,
1867 GLuint n, const GLfloat texcoords[][4],
1868 const GLfloat lambda_iso[], GLfloat rgba[][4])
1869 {
1870 const struct gl_texture_image *tImg = _mesa_base_tex_image(tObj);
1871 const struct swrast_texture_image *swImg = swrast_texture_image_const(tImg);
1872 const GLfloat maxEccentricity =
1873 samp->MaxAnisotropy * samp->MaxAnisotropy;
1874
1875 /* re-calculate the lambda values so that they are usable with anisotropic
1876 * filtering
1877 */
1878 SWspan *span = (SWspan *)lambda_iso; /* access the "hidden" SWspan struct */
1879
1880 /* based on interpolate_texcoords(struct gl_context *ctx, SWspan *span)
1881 * in swrast/s_span.c
1882 */
1883
1884 /* find the texture unit index by looking up the current texture object
1885 * from the context list of available texture objects.
1886 */
1887 const GLuint u = texture_unit_index(ctx, tObj);
1888 const GLuint attr = VARYING_SLOT_TEX0 + u;
1889 GLfloat texW, texH;
1890
1891 const GLfloat dsdx = span->attrStepX[attr][0];
1892 const GLfloat dsdy = span->attrStepY[attr][0];
1893 const GLfloat dtdx = span->attrStepX[attr][1];
1894 const GLfloat dtdy = span->attrStepY[attr][1];
1895 const GLfloat dqdx = span->attrStepX[attr][3];
1896 const GLfloat dqdy = span->attrStepY[attr][3];
1897 GLfloat s = span->attrStart[attr][0] + span->leftClip * dsdx;
1898 GLfloat t = span->attrStart[attr][1] + span->leftClip * dtdx;
1899 GLfloat q = span->attrStart[attr][3] + span->leftClip * dqdx;
1900
1901 /* from swrast/s_texcombine.c _swrast_texture_span */
1902 const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[u];
1903 const GLboolean adjustLOD =
1904 (texUnit->LodBias + samp->LodBias != 0.0F)
1905 || (samp->MinLod != -1000.0F || samp->MaxLod != 1000.0F);
1906
1907 GLuint i;
1908
1909 /* on first access create the lookup table containing the filter weights. */
1910 if (!weightLut) {
1911 create_filter_table();
1912 }
1913
1914 texW = swImg->WidthScale;
1915 texH = swImg->HeightScale;
1916
1917 for (i = 0; i < n; i++) {
1918 const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
1919
1920 GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ);
1921 GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ);
1922 GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ);
1923 GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ);
1924
1925 /* note: instead of working with Px and Py, we will use the
1926 * squared length instead, to avoid sqrt.
1927 */
1928 GLfloat Px2 = dudx * dudx + dvdx * dvdx;
1929 GLfloat Py2 = dudy * dudy + dvdy * dvdy;
1930
1931 GLfloat Pmax2;
1932 GLfloat Pmin2;
1933 GLfloat e;
1934 GLfloat lod;
1935
1936 s += dsdx;
1937 t += dtdx;
1938 q += dqdx;
1939
1940 if (Px2 < Py2) {
1941 Pmax2 = Py2;
1942 Pmin2 = Px2;
1943 }
1944 else {
1945 Pmax2 = Px2;
1946 Pmin2 = Py2;
1947 }
1948
1949 /* if the eccentricity of the ellipse is too big, scale up the shorter
1950 * of the two vectors to limit the maximum amount of work per pixel
1951 */
1952 e = Pmax2 / Pmin2;
1953 if (e > maxEccentricity) {
1954 /* GLfloat s=e / maxEccentricity;
1955 minor[0] *= s;
1956 minor[1] *= s;
1957 Pmin2 *= s; */
1958 Pmin2 = Pmax2 / maxEccentricity;
1959 }
1960
1961 /* note: we need to have Pmin=sqrt(Pmin2) here, but we can avoid
1962 * this since 0.5*log(x) = log(sqrt(x))
1963 */
1964 lod = 0.5f * log2f(Pmin2);
1965
1966 if (adjustLOD) {
1967 /* from swrast/s_texcombine.c _swrast_texture_span */
1968 if (texUnit->LodBias + samp->LodBias != 0.0F) {
1969 /* apply LOD bias, but don't clamp yet */
1970 const GLfloat bias =
1971 CLAMP(texUnit->LodBias + samp->LodBias,
1972 -ctx->Const.MaxTextureLodBias,
1973 ctx->Const.MaxTextureLodBias);
1974 lod += bias;
1975
1976 if (samp->MinLod != -1000.0F ||
1977 samp->MaxLod != 1000.0F) {
1978 /* apply LOD clamping to lambda */
1979 lod = CLAMP(lod, samp->MinLod, samp->MaxLod);
1980 }
1981 }
1982 }
1983
1984 /* If the ellipse covers the whole image, we can
1985 * simply return the average of the whole image.
1986 */
1987 if (lod >= tObj->_MaxLevel) {
1988 sample_2d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
1989 texcoords[i], rgba[i]);
1990 }
1991 else {
1992 /* don't bother interpolating between multiple LODs; it doesn't
1993 * seem to be worth the extra running time.
1994 */
1995 sample_2d_ewa(ctx, samp, tObj, texcoords[i],
1996 dudx, dvdx, dudy, dvdy, (GLint) floorf(lod), rgba[i]);
1997
1998 /* unused: */
1999 (void) sample_2d_footprint;
2000 /*
2001 sample_2d_footprint(ctx, tObj, texcoords[i],
2002 dudx, dvdx, dudy, dvdy, floor(lod), rgba[i]);
2003 */
2004 }
2005 }
2006 }
2007
2008
2009
2010 /**********************************************************************/
2011 /* 3-D Texture Sampling Functions */
2012 /**********************************************************************/
2013
2014 /**
2015 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
2016 */
2017 static void
sample_3d_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[4])2018 sample_3d_nearest(struct gl_context *ctx,
2019 const struct gl_sampler_object *samp,
2020 const struct gl_texture_image *img,
2021 const GLfloat texcoord[4],
2022 GLfloat rgba[4])
2023 {
2024 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
2025 const GLint width = img->Width2; /* without border, power of two */
2026 const GLint height = img->Height2; /* without border, power of two */
2027 const GLint depth = img->Depth2; /* without border, power of two */
2028 GLint i, j, k;
2029 (void) ctx;
2030
2031 i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
2032 j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
2033 k = nearest_texel_location(samp->WrapR, img, depth, texcoord[2]);
2034
2035 if (i < 0 || i >= (GLint) img->Width ||
2036 j < 0 || j >= (GLint) img->Height ||
2037 k < 0 || k >= (GLint) img->Depth) {
2038 /* Need this test for GL_CLAMP_TO_BORDER mode */
2039 get_border_color(samp, img, rgba);
2040 }
2041 else {
2042 swImg->FetchTexel(swImg, i, j, k, rgba);
2043 }
2044 }
2045
2046
2047 /**
2048 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
2049 */
2050 static void
sample_3d_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[4])2051 sample_3d_linear(struct gl_context *ctx,
2052 const struct gl_sampler_object *samp,
2053 const struct gl_texture_image *img,
2054 const GLfloat texcoord[4],
2055 GLfloat rgba[4])
2056 {
2057 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
2058 const GLint width = img->Width2;
2059 const GLint height = img->Height2;
2060 const GLint depth = img->Depth2;
2061 GLint i0, j0, k0, i1, j1, k1;
2062 GLbitfield useBorderColor = 0x0;
2063 GLfloat a, b, c;
2064 GLfloat t000[4], t010[4], t001[4], t011[4];
2065 GLfloat t100[4], t110[4], t101[4], t111[4];
2066
2067 linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a);
2068 linear_texel_locations(samp->WrapT, img, height, texcoord[1], &j0, &j1, &b);
2069 linear_texel_locations(samp->WrapR, img, depth, texcoord[2], &k0, &k1, &c);
2070
2071 if (img->Border) {
2072 i0 += img->Border;
2073 i1 += img->Border;
2074 j0 += img->Border;
2075 j1 += img->Border;
2076 k0 += img->Border;
2077 k1 += img->Border;
2078 }
2079 else {
2080 /* check if sampling texture border color */
2081 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
2082 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
2083 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
2084 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
2085 if (k0 < 0 || k0 >= depth) useBorderColor |= K0BIT;
2086 if (k1 < 0 || k1 >= depth) useBorderColor |= K1BIT;
2087 }
2088
2089 /* Fetch texels */
2090 if (useBorderColor & (I0BIT | J0BIT | K0BIT)) {
2091 get_border_color(samp, img, t000);
2092 }
2093 else {
2094 swImg->FetchTexel(swImg, i0, j0, k0, t000);
2095 }
2096 if (useBorderColor & (I1BIT | J0BIT | K0BIT)) {
2097 get_border_color(samp, img, t100);
2098 }
2099 else {
2100 swImg->FetchTexel(swImg, i1, j0, k0, t100);
2101 }
2102 if (useBorderColor & (I0BIT | J1BIT | K0BIT)) {
2103 get_border_color(samp, img, t010);
2104 }
2105 else {
2106 swImg->FetchTexel(swImg, i0, j1, k0, t010);
2107 }
2108 if (useBorderColor & (I1BIT | J1BIT | K0BIT)) {
2109 get_border_color(samp, img, t110);
2110 }
2111 else {
2112 swImg->FetchTexel(swImg, i1, j1, k0, t110);
2113 }
2114
2115 if (useBorderColor & (I0BIT | J0BIT | K1BIT)) {
2116 get_border_color(samp, img, t001);
2117 }
2118 else {
2119 swImg->FetchTexel(swImg, i0, j0, k1, t001);
2120 }
2121 if (useBorderColor & (I1BIT | J0BIT | K1BIT)) {
2122 get_border_color(samp, img, t101);
2123 }
2124 else {
2125 swImg->FetchTexel(swImg, i1, j0, k1, t101);
2126 }
2127 if (useBorderColor & (I0BIT | J1BIT | K1BIT)) {
2128 get_border_color(samp, img, t011);
2129 }
2130 else {
2131 swImg->FetchTexel(swImg, i0, j1, k1, t011);
2132 }
2133 if (useBorderColor & (I1BIT | J1BIT | K1BIT)) {
2134 get_border_color(samp, img, t111);
2135 }
2136 else {
2137 swImg->FetchTexel(swImg, i1, j1, k1, t111);
2138 }
2139
2140 /* trilinear interpolation of samples */
2141 lerp_rgba_3d(rgba, a, b, c, t000, t100, t010, t110, t001, t101, t011, t111);
2142 }
2143
2144
2145 static void
sample_3d_nearest_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2146 sample_3d_nearest_mipmap_nearest(struct gl_context *ctx,
2147 const struct gl_sampler_object *samp,
2148 const struct gl_texture_object *tObj,
2149 GLuint n, const GLfloat texcoord[][4],
2150 const GLfloat lambda[], GLfloat rgba[][4] )
2151 {
2152 GLuint i;
2153 for (i = 0; i < n; i++) {
2154 GLint level = nearest_mipmap_level(tObj, lambda[i]);
2155 sample_3d_nearest(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
2156 }
2157 }
2158
2159
2160 static void
sample_3d_linear_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2161 sample_3d_linear_mipmap_nearest(struct gl_context *ctx,
2162 const struct gl_sampler_object *samp,
2163 const struct gl_texture_object *tObj,
2164 GLuint n, const GLfloat texcoord[][4],
2165 const GLfloat lambda[], GLfloat rgba[][4])
2166 {
2167 GLuint i;
2168 assert(lambda != NULL);
2169 for (i = 0; i < n; i++) {
2170 GLint level = nearest_mipmap_level(tObj, lambda[i]);
2171 sample_3d_linear(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
2172 }
2173 }
2174
2175
2176 static void
sample_3d_nearest_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2177 sample_3d_nearest_mipmap_linear(struct gl_context *ctx,
2178 const struct gl_sampler_object *samp,
2179 const struct gl_texture_object *tObj,
2180 GLuint n, const GLfloat texcoord[][4],
2181 const GLfloat lambda[], GLfloat rgba[][4])
2182 {
2183 GLuint i;
2184 assert(lambda != NULL);
2185 for (i = 0; i < n; i++) {
2186 GLint level = linear_mipmap_level(tObj, lambda[i]);
2187 if (level >= tObj->_MaxLevel) {
2188 sample_3d_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
2189 texcoord[i], rgba[i]);
2190 }
2191 else {
2192 GLfloat t0[4], t1[4]; /* texels */
2193 const GLfloat f = FRAC(lambda[i]);
2194 sample_3d_nearest(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
2195 sample_3d_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
2196 lerp_rgba(rgba[i], f, t0, t1);
2197 }
2198 }
2199 }
2200
2201
2202 static void
sample_3d_linear_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2203 sample_3d_linear_mipmap_linear(struct gl_context *ctx,
2204 const struct gl_sampler_object *samp,
2205 const struct gl_texture_object *tObj,
2206 GLuint n, const GLfloat texcoord[][4],
2207 const GLfloat lambda[], GLfloat rgba[][4])
2208 {
2209 GLuint i;
2210 assert(lambda != NULL);
2211 for (i = 0; i < n; i++) {
2212 GLint level = linear_mipmap_level(tObj, lambda[i]);
2213 if (level >= tObj->_MaxLevel) {
2214 sample_3d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
2215 texcoord[i], rgba[i]);
2216 }
2217 else {
2218 GLfloat t0[4], t1[4]; /* texels */
2219 const GLfloat f = FRAC(lambda[i]);
2220 sample_3d_linear(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
2221 sample_3d_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
2222 lerp_rgba(rgba[i], f, t0, t1);
2223 }
2224 }
2225 }
2226
2227
2228 /** Sample 3D texture, nearest filtering for both min/magnification */
2229 static void
sample_nearest_3d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])2230 sample_nearest_3d(struct gl_context *ctx,
2231 const struct gl_sampler_object *samp,
2232 const struct gl_texture_object *tObj, GLuint n,
2233 const GLfloat texcoords[][4], const GLfloat lambda[],
2234 GLfloat rgba[][4])
2235 {
2236 GLuint i;
2237 const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
2238 (void) lambda;
2239 for (i = 0; i < n; i++) {
2240 sample_3d_nearest(ctx, samp, image, texcoords[i], rgba[i]);
2241 }
2242 }
2243
2244
2245 /** Sample 3D texture, linear filtering for both min/magnification */
2246 static void
sample_linear_3d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])2247 sample_linear_3d(struct gl_context *ctx,
2248 const struct gl_sampler_object *samp,
2249 const struct gl_texture_object *tObj, GLuint n,
2250 const GLfloat texcoords[][4],
2251 const GLfloat lambda[], GLfloat rgba[][4])
2252 {
2253 GLuint i;
2254 const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
2255 (void) lambda;
2256 for (i = 0; i < n; i++) {
2257 sample_3d_linear(ctx, samp, image, texcoords[i], rgba[i]);
2258 }
2259 }
2260
2261
2262 /** Sample 3D texture, using lambda to choose between min/magnification */
2263 static void
sample_lambda_3d(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])2264 sample_lambda_3d(struct gl_context *ctx,
2265 const struct gl_sampler_object *samp,
2266 const struct gl_texture_object *tObj, GLuint n,
2267 const GLfloat texcoords[][4], const GLfloat lambda[],
2268 GLfloat rgba[][4])
2269 {
2270 GLuint minStart, minEnd; /* texels with minification */
2271 GLuint magStart, magEnd; /* texels with magnification */
2272 GLuint i;
2273
2274 assert(lambda != NULL);
2275 compute_min_mag_ranges(samp, n, lambda,
2276 &minStart, &minEnd, &magStart, &magEnd);
2277
2278 if (minStart < minEnd) {
2279 /* do the minified texels */
2280 GLuint m = minEnd - minStart;
2281 switch (samp->MinFilter) {
2282 case GL_NEAREST:
2283 for (i = minStart; i < minEnd; i++)
2284 sample_3d_nearest(ctx, samp, _mesa_base_tex_image(tObj),
2285 texcoords[i], rgba[i]);
2286 break;
2287 case GL_LINEAR:
2288 for (i = minStart; i < minEnd; i++)
2289 sample_3d_linear(ctx, samp, _mesa_base_tex_image(tObj),
2290 texcoords[i], rgba[i]);
2291 break;
2292 case GL_NEAREST_MIPMAP_NEAREST:
2293 sample_3d_nearest_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
2294 lambda + minStart, rgba + minStart);
2295 break;
2296 case GL_LINEAR_MIPMAP_NEAREST:
2297 sample_3d_linear_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
2298 lambda + minStart, rgba + minStart);
2299 break;
2300 case GL_NEAREST_MIPMAP_LINEAR:
2301 sample_3d_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
2302 lambda + minStart, rgba + minStart);
2303 break;
2304 case GL_LINEAR_MIPMAP_LINEAR:
2305 sample_3d_linear_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
2306 lambda + minStart, rgba + minStart);
2307 break;
2308 default:
2309 _mesa_problem(ctx, "Bad min filter in sample_3d_texture");
2310 return;
2311 }
2312 }
2313
2314 if (magStart < magEnd) {
2315 /* do the magnified texels */
2316 switch (samp->MagFilter) {
2317 case GL_NEAREST:
2318 for (i = magStart; i < magEnd; i++)
2319 sample_3d_nearest(ctx, samp, _mesa_base_tex_image(tObj),
2320 texcoords[i], rgba[i]);
2321 break;
2322 case GL_LINEAR:
2323 for (i = magStart; i < magEnd; i++)
2324 sample_3d_linear(ctx, samp, _mesa_base_tex_image(tObj),
2325 texcoords[i], rgba[i]);
2326 break;
2327 default:
2328 _mesa_problem(ctx, "Bad mag filter in sample_3d_texture");
2329 return;
2330 }
2331 }
2332 }
2333
2334
2335 /**********************************************************************/
2336 /* Texture Cube Map Sampling Functions */
2337 /**********************************************************************/
2338
2339 /**
2340 * Choose one of six sides of a texture cube map given the texture
2341 * coord (rx,ry,rz). Return pointer to corresponding array of texture
2342 * images.
2343 */
2344 static const struct gl_texture_image **
choose_cube_face(const struct gl_texture_object * texObj,const GLfloat texcoord[4],GLfloat newCoord[4])2345 choose_cube_face(const struct gl_texture_object *texObj,
2346 const GLfloat texcoord[4], GLfloat newCoord[4])
2347 {
2348 /*
2349 major axis
2350 direction target sc tc ma
2351 ---------- ------------------------------- --- --- ---
2352 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
2353 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
2354 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
2355 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
2356 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
2357 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
2358 */
2359 const GLfloat rx = texcoord[0];
2360 const GLfloat ry = texcoord[1];
2361 const GLfloat rz = texcoord[2];
2362 const GLfloat arx = fabsf(rx), ary = fabsf(ry), arz = fabsf(rz);
2363 GLuint face;
2364 GLfloat sc, tc, ma;
2365
2366 if (arx >= ary && arx >= arz) {
2367 if (rx >= 0.0F) {
2368 face = FACE_POS_X;
2369 sc = -rz;
2370 tc = -ry;
2371 ma = arx;
2372 }
2373 else {
2374 face = FACE_NEG_X;
2375 sc = rz;
2376 tc = -ry;
2377 ma = arx;
2378 }
2379 }
2380 else if (ary >= arx && ary >= arz) {
2381 if (ry >= 0.0F) {
2382 face = FACE_POS_Y;
2383 sc = rx;
2384 tc = rz;
2385 ma = ary;
2386 }
2387 else {
2388 face = FACE_NEG_Y;
2389 sc = rx;
2390 tc = -rz;
2391 ma = ary;
2392 }
2393 }
2394 else {
2395 if (rz > 0.0F) {
2396 face = FACE_POS_Z;
2397 sc = rx;
2398 tc = -ry;
2399 ma = arz;
2400 }
2401 else {
2402 face = FACE_NEG_Z;
2403 sc = -rx;
2404 tc = -ry;
2405 ma = arz;
2406 }
2407 }
2408
2409 {
2410 const float ima = 1.0F / ma;
2411 newCoord[0] = ( sc * ima + 1.0F ) * 0.5F;
2412 newCoord[1] = ( tc * ima + 1.0F ) * 0.5F;
2413 }
2414
2415 return (const struct gl_texture_image **) texObj->Image[face];
2416 }
2417
2418
2419 static void
sample_nearest_cube(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])2420 sample_nearest_cube(struct gl_context *ctx,
2421 const struct gl_sampler_object *samp,
2422 const struct gl_texture_object *tObj, GLuint n,
2423 const GLfloat texcoords[][4], const GLfloat lambda[],
2424 GLfloat rgba[][4])
2425 {
2426 GLuint i;
2427 (void) lambda;
2428 for (i = 0; i < n; i++) {
2429 const struct gl_texture_image **images;
2430 GLfloat newCoord[4];
2431 images = choose_cube_face(tObj, texcoords[i], newCoord);
2432 sample_2d_nearest(ctx, samp, images[tObj->BaseLevel],
2433 newCoord, rgba[i]);
2434 }
2435 if (is_depth_texture(tObj)) {
2436 for (i = 0; i < n; i++) {
2437 apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
2438 }
2439 }
2440 }
2441
2442
2443 static void
sample_linear_cube(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])2444 sample_linear_cube(struct gl_context *ctx,
2445 const struct gl_sampler_object *samp,
2446 const struct gl_texture_object *tObj, GLuint n,
2447 const GLfloat texcoords[][4],
2448 const GLfloat lambda[], GLfloat rgba[][4])
2449 {
2450 GLuint i;
2451 (void) lambda;
2452 for (i = 0; i < n; i++) {
2453 const struct gl_texture_image **images;
2454 GLfloat newCoord[4];
2455 images = choose_cube_face(tObj, texcoords[i], newCoord);
2456 sample_2d_linear(ctx, samp, images[tObj->BaseLevel],
2457 newCoord, rgba[i]);
2458 }
2459 if (is_depth_texture(tObj)) {
2460 for (i = 0; i < n; i++) {
2461 apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
2462 }
2463 }
2464 }
2465
2466
2467 static void
sample_cube_nearest_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2468 sample_cube_nearest_mipmap_nearest(struct gl_context *ctx,
2469 const struct gl_sampler_object *samp,
2470 const struct gl_texture_object *tObj,
2471 GLuint n, const GLfloat texcoord[][4],
2472 const GLfloat lambda[], GLfloat rgba[][4])
2473 {
2474 GLuint i;
2475 assert(lambda != NULL);
2476 for (i = 0; i < n; i++) {
2477 const struct gl_texture_image **images;
2478 GLfloat newCoord[4];
2479 GLint level;
2480 images = choose_cube_face(tObj, texcoord[i], newCoord);
2481
2482 /* XXX we actually need to recompute lambda here based on the newCoords.
2483 * But we would need the texcoords of adjacent fragments to compute that
2484 * properly, and we don't have those here.
2485 * For now, do an approximation: subtracting 1 from the chosen mipmap
2486 * level seems to work in some test cases.
2487 * The same adjustment is done in the next few functions.
2488 */
2489 level = nearest_mipmap_level(tObj, lambda[i]);
2490 level = MAX2(level - 1, 0);
2491
2492 sample_2d_nearest(ctx, samp, images[level], newCoord, rgba[i]);
2493 }
2494 if (is_depth_texture(tObj)) {
2495 for (i = 0; i < n; i++) {
2496 apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
2497 }
2498 }
2499 }
2500
2501
2502 static void
sample_cube_linear_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2503 sample_cube_linear_mipmap_nearest(struct gl_context *ctx,
2504 const struct gl_sampler_object *samp,
2505 const struct gl_texture_object *tObj,
2506 GLuint n, const GLfloat texcoord[][4],
2507 const GLfloat lambda[], GLfloat rgba[][4])
2508 {
2509 GLuint i;
2510 assert(lambda != NULL);
2511 for (i = 0; i < n; i++) {
2512 const struct gl_texture_image **images;
2513 GLfloat newCoord[4];
2514 GLint level = nearest_mipmap_level(tObj, lambda[i]);
2515 level = MAX2(level - 1, 0); /* see comment above */
2516 images = choose_cube_face(tObj, texcoord[i], newCoord);
2517 sample_2d_linear(ctx, samp, images[level], newCoord, rgba[i]);
2518 }
2519 if (is_depth_texture(tObj)) {
2520 for (i = 0; i < n; i++) {
2521 apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
2522 }
2523 }
2524 }
2525
2526
2527 static void
sample_cube_nearest_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2528 sample_cube_nearest_mipmap_linear(struct gl_context *ctx,
2529 const struct gl_sampler_object *samp,
2530 const struct gl_texture_object *tObj,
2531 GLuint n, const GLfloat texcoord[][4],
2532 const GLfloat lambda[], GLfloat rgba[][4])
2533 {
2534 GLuint i;
2535 assert(lambda != NULL);
2536 for (i = 0; i < n; i++) {
2537 const struct gl_texture_image **images;
2538 GLfloat newCoord[4];
2539 GLint level = linear_mipmap_level(tObj, lambda[i]);
2540 level = MAX2(level - 1, 0); /* see comment above */
2541 images = choose_cube_face(tObj, texcoord[i], newCoord);
2542 if (level >= tObj->_MaxLevel) {
2543 sample_2d_nearest(ctx, samp, images[tObj->_MaxLevel],
2544 newCoord, rgba[i]);
2545 }
2546 else {
2547 GLfloat t0[4], t1[4]; /* texels */
2548 const GLfloat f = FRAC(lambda[i]);
2549 sample_2d_nearest(ctx, samp, images[level ], newCoord, t0);
2550 sample_2d_nearest(ctx, samp, images[level+1], newCoord, t1);
2551 lerp_rgba(rgba[i], f, t0, t1);
2552 }
2553 }
2554 if (is_depth_texture(tObj)) {
2555 for (i = 0; i < n; i++) {
2556 apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
2557 }
2558 }
2559 }
2560
2561
2562 static void
sample_cube_linear_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2563 sample_cube_linear_mipmap_linear(struct gl_context *ctx,
2564 const struct gl_sampler_object *samp,
2565 const struct gl_texture_object *tObj,
2566 GLuint n, const GLfloat texcoord[][4],
2567 const GLfloat lambda[], GLfloat rgba[][4])
2568 {
2569 GLuint i;
2570 assert(lambda != NULL);
2571 for (i = 0; i < n; i++) {
2572 const struct gl_texture_image **images;
2573 GLfloat newCoord[4];
2574 GLint level = linear_mipmap_level(tObj, lambda[i]);
2575 level = MAX2(level - 1, 0); /* see comment above */
2576 images = choose_cube_face(tObj, texcoord[i], newCoord);
2577 if (level >= tObj->_MaxLevel) {
2578 sample_2d_linear(ctx, samp, images[tObj->_MaxLevel],
2579 newCoord, rgba[i]);
2580 }
2581 else {
2582 GLfloat t0[4], t1[4];
2583 const GLfloat f = FRAC(lambda[i]);
2584 sample_2d_linear(ctx, samp, images[level ], newCoord, t0);
2585 sample_2d_linear(ctx, samp, images[level+1], newCoord, t1);
2586 lerp_rgba(rgba[i], f, t0, t1);
2587 }
2588 }
2589 if (is_depth_texture(tObj)) {
2590 for (i = 0; i < n; i++) {
2591 apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
2592 }
2593 }
2594 }
2595
2596
2597 /** Sample cube texture, using lambda to choose between min/magnification */
2598 static void
sample_lambda_cube(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])2599 sample_lambda_cube(struct gl_context *ctx,
2600 const struct gl_sampler_object *samp,
2601 const struct gl_texture_object *tObj, GLuint n,
2602 const GLfloat texcoords[][4], const GLfloat lambda[],
2603 GLfloat rgba[][4])
2604 {
2605 GLuint minStart, minEnd; /* texels with minification */
2606 GLuint magStart, magEnd; /* texels with magnification */
2607
2608 assert(lambda != NULL);
2609 compute_min_mag_ranges(samp, n, lambda,
2610 &minStart, &minEnd, &magStart, &magEnd);
2611
2612 if (minStart < minEnd) {
2613 /* do the minified texels */
2614 const GLuint m = minEnd - minStart;
2615 switch (samp->MinFilter) {
2616 case GL_NEAREST:
2617 sample_nearest_cube(ctx, samp, tObj, m, texcoords + minStart,
2618 lambda + minStart, rgba + minStart);
2619 break;
2620 case GL_LINEAR:
2621 sample_linear_cube(ctx, samp, tObj, m, texcoords + minStart,
2622 lambda + minStart, rgba + minStart);
2623 break;
2624 case GL_NEAREST_MIPMAP_NEAREST:
2625 sample_cube_nearest_mipmap_nearest(ctx, samp, tObj, m,
2626 texcoords + minStart,
2627 lambda + minStart, rgba + minStart);
2628 break;
2629 case GL_LINEAR_MIPMAP_NEAREST:
2630 sample_cube_linear_mipmap_nearest(ctx, samp, tObj, m,
2631 texcoords + minStart,
2632 lambda + minStart, rgba + minStart);
2633 break;
2634 case GL_NEAREST_MIPMAP_LINEAR:
2635 sample_cube_nearest_mipmap_linear(ctx, samp, tObj, m,
2636 texcoords + minStart,
2637 lambda + minStart, rgba + minStart);
2638 break;
2639 case GL_LINEAR_MIPMAP_LINEAR:
2640 sample_cube_linear_mipmap_linear(ctx, samp, tObj, m,
2641 texcoords + minStart,
2642 lambda + minStart, rgba + minStart);
2643 break;
2644 default:
2645 _mesa_problem(ctx, "Bad min filter in sample_lambda_cube");
2646 break;
2647 }
2648 }
2649
2650 if (magStart < magEnd) {
2651 /* do the magnified texels */
2652 const GLuint m = magEnd - magStart;
2653 switch (samp->MagFilter) {
2654 case GL_NEAREST:
2655 sample_nearest_cube(ctx, samp, tObj, m, texcoords + magStart,
2656 lambda + magStart, rgba + magStart);
2657 break;
2658 case GL_LINEAR:
2659 sample_linear_cube(ctx, samp, tObj, m, texcoords + magStart,
2660 lambda + magStart, rgba + magStart);
2661 break;
2662 default:
2663 _mesa_problem(ctx, "Bad mag filter in sample_lambda_cube");
2664 break;
2665 }
2666 }
2667 }
2668
2669
2670 /**********************************************************************/
2671 /* Texture Rectangle Sampling Functions */
2672 /**********************************************************************/
2673
2674
2675 static void
sample_nearest_rect(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])2676 sample_nearest_rect(struct gl_context *ctx,
2677 const struct gl_sampler_object *samp,
2678 const struct gl_texture_object *tObj, GLuint n,
2679 const GLfloat texcoords[][4], const GLfloat lambda[],
2680 GLfloat rgba[][4])
2681 {
2682 const struct gl_texture_image *img = tObj->Image[0][0];
2683 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
2684 const GLint width = img->Width;
2685 const GLint height = img->Height;
2686 GLuint i;
2687
2688 (void) ctx;
2689 (void) lambda;
2690
2691 assert(samp->WrapS == GL_CLAMP ||
2692 samp->WrapS == GL_CLAMP_TO_EDGE ||
2693 samp->WrapS == GL_CLAMP_TO_BORDER);
2694 assert(samp->WrapT == GL_CLAMP ||
2695 samp->WrapT == GL_CLAMP_TO_EDGE ||
2696 samp->WrapT == GL_CLAMP_TO_BORDER);
2697
2698 for (i = 0; i < n; i++) {
2699 GLint row, col;
2700 col = clamp_rect_coord_nearest(samp->WrapS, texcoords[i][0], width);
2701 row = clamp_rect_coord_nearest(samp->WrapT, texcoords[i][1], height);
2702 if (col < 0 || col >= width || row < 0 || row >= height)
2703 get_border_color(samp, img, rgba[i]);
2704 else
2705 swImg->FetchTexel(swImg, col, row, 0, rgba[i]);
2706 }
2707 }
2708
2709
2710 static void
sample_linear_rect(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])2711 sample_linear_rect(struct gl_context *ctx,
2712 const struct gl_sampler_object *samp,
2713 const struct gl_texture_object *tObj, GLuint n,
2714 const GLfloat texcoords[][4],
2715 const GLfloat lambda[], GLfloat rgba[][4])
2716 {
2717 const struct gl_texture_image *img = tObj->Image[0][0];
2718 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
2719 const GLint width = img->Width;
2720 const GLint height = img->Height;
2721 GLuint i;
2722
2723 (void) ctx;
2724 (void) lambda;
2725
2726 assert(samp->WrapS == GL_CLAMP ||
2727 samp->WrapS == GL_CLAMP_TO_EDGE ||
2728 samp->WrapS == GL_CLAMP_TO_BORDER);
2729 assert(samp->WrapT == GL_CLAMP ||
2730 samp->WrapT == GL_CLAMP_TO_EDGE ||
2731 samp->WrapT == GL_CLAMP_TO_BORDER);
2732
2733 for (i = 0; i < n; i++) {
2734 GLint i0, j0, i1, j1;
2735 GLfloat t00[4], t01[4], t10[4], t11[4];
2736 GLfloat a, b;
2737 GLbitfield useBorderColor = 0x0;
2738
2739 clamp_rect_coord_linear(samp->WrapS, texcoords[i][0], width,
2740 &i0, &i1, &a);
2741 clamp_rect_coord_linear(samp->WrapT, texcoords[i][1], height,
2742 &j0, &j1, &b);
2743
2744 /* compute integer rows/columns */
2745 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
2746 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
2747 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
2748 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
2749
2750 /* get four texel samples */
2751 if (useBorderColor & (I0BIT | J0BIT))
2752 get_border_color(samp, img, t00);
2753 else
2754 swImg->FetchTexel(swImg, i0, j0, 0, t00);
2755
2756 if (useBorderColor & (I1BIT | J0BIT))
2757 get_border_color(samp, img, t10);
2758 else
2759 swImg->FetchTexel(swImg, i1, j0, 0, t10);
2760
2761 if (useBorderColor & (I0BIT | J1BIT))
2762 get_border_color(samp, img, t01);
2763 else
2764 swImg->FetchTexel(swImg, i0, j1, 0, t01);
2765
2766 if (useBorderColor & (I1BIT | J1BIT))
2767 get_border_color(samp, img, t11);
2768 else
2769 swImg->FetchTexel(swImg, i1, j1, 0, t11);
2770
2771 lerp_rgba_2d(rgba[i], a, b, t00, t10, t01, t11);
2772 }
2773 }
2774
2775
2776 /** Sample Rect texture, using lambda to choose between min/magnification */
2777 static void
sample_lambda_rect(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])2778 sample_lambda_rect(struct gl_context *ctx,
2779 const struct gl_sampler_object *samp,
2780 const struct gl_texture_object *tObj, GLuint n,
2781 const GLfloat texcoords[][4], const GLfloat lambda[],
2782 GLfloat rgba[][4])
2783 {
2784 GLuint minStart, minEnd, magStart, magEnd;
2785
2786 /* We only need lambda to decide between minification and magnification.
2787 * There is no mipmapping with rectangular textures.
2788 */
2789 compute_min_mag_ranges(samp, n, lambda,
2790 &minStart, &minEnd, &magStart, &magEnd);
2791
2792 if (minStart < minEnd) {
2793 if (samp->MinFilter == GL_NEAREST) {
2794 sample_nearest_rect(ctx, samp, tObj, minEnd - minStart,
2795 texcoords + minStart, NULL, rgba + minStart);
2796 }
2797 else {
2798 sample_linear_rect(ctx, samp, tObj, minEnd - minStart,
2799 texcoords + minStart, NULL, rgba + minStart);
2800 }
2801 }
2802 if (magStart < magEnd) {
2803 if (samp->MagFilter == GL_NEAREST) {
2804 sample_nearest_rect(ctx, samp, tObj, magEnd - magStart,
2805 texcoords + magStart, NULL, rgba + magStart);
2806 }
2807 else {
2808 sample_linear_rect(ctx, samp, tObj, magEnd - magStart,
2809 texcoords + magStart, NULL, rgba + magStart);
2810 }
2811 }
2812 }
2813
2814
2815 /**********************************************************************/
2816 /* 2D Texture Array Sampling Functions */
2817 /**********************************************************************/
2818
2819 /**
2820 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
2821 */
2822 static void
sample_2d_array_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[4])2823 sample_2d_array_nearest(struct gl_context *ctx,
2824 const struct gl_sampler_object *samp,
2825 const struct gl_texture_image *img,
2826 const GLfloat texcoord[4],
2827 GLfloat rgba[4])
2828 {
2829 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
2830 const GLint width = img->Width2; /* without border, power of two */
2831 const GLint height = img->Height2; /* without border, power of two */
2832 const GLint depth = img->Depth;
2833 GLint i, j;
2834 GLint array;
2835 (void) ctx;
2836
2837 i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
2838 j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
2839 array = tex_array_slice(texcoord[2], depth);
2840
2841 if (i < 0 || i >= (GLint) img->Width ||
2842 j < 0 || j >= (GLint) img->Height ||
2843 array < 0 || array >= (GLint) img->Depth) {
2844 /* Need this test for GL_CLAMP_TO_BORDER mode */
2845 get_border_color(samp, img, rgba);
2846 }
2847 else {
2848 swImg->FetchTexel(swImg, i, j, array, rgba);
2849 }
2850 }
2851
2852
2853 /**
2854 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
2855 */
2856 static void
sample_2d_array_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[4])2857 sample_2d_array_linear(struct gl_context *ctx,
2858 const struct gl_sampler_object *samp,
2859 const struct gl_texture_image *img,
2860 const GLfloat texcoord[4],
2861 GLfloat rgba[4])
2862 {
2863 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
2864 const GLint width = img->Width2;
2865 const GLint height = img->Height2;
2866 const GLint depth = img->Depth;
2867 GLint i0, j0, i1, j1;
2868 GLint array;
2869 GLbitfield useBorderColor = 0x0;
2870 GLfloat a, b;
2871 GLfloat t00[4], t01[4], t10[4], t11[4];
2872
2873 linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a);
2874 linear_texel_locations(samp->WrapT, img, height, texcoord[1], &j0, &j1, &b);
2875 array = tex_array_slice(texcoord[2], depth);
2876
2877 if (array < 0 || array >= depth) {
2878 COPY_4V(rgba, samp->BorderColor.f);
2879 }
2880 else {
2881 if (img->Border) {
2882 i0 += img->Border;
2883 i1 += img->Border;
2884 j0 += img->Border;
2885 j1 += img->Border;
2886 }
2887 else {
2888 /* check if sampling texture border color */
2889 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
2890 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
2891 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
2892 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
2893 }
2894
2895 /* Fetch texels */
2896 if (useBorderColor & (I0BIT | J0BIT)) {
2897 get_border_color(samp, img, t00);
2898 }
2899 else {
2900 swImg->FetchTexel(swImg, i0, j0, array, t00);
2901 }
2902 if (useBorderColor & (I1BIT | J0BIT)) {
2903 get_border_color(samp, img, t10);
2904 }
2905 else {
2906 swImg->FetchTexel(swImg, i1, j0, array, t10);
2907 }
2908 if (useBorderColor & (I0BIT | J1BIT)) {
2909 get_border_color(samp, img, t01);
2910 }
2911 else {
2912 swImg->FetchTexel(swImg, i0, j1, array, t01);
2913 }
2914 if (useBorderColor & (I1BIT | J1BIT)) {
2915 get_border_color(samp, img, t11);
2916 }
2917 else {
2918 swImg->FetchTexel(swImg, i1, j1, array, t11);
2919 }
2920
2921 /* trilinear interpolation of samples */
2922 lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11);
2923 }
2924 }
2925
2926
2927 static void
sample_2d_array_nearest_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2928 sample_2d_array_nearest_mipmap_nearest(struct gl_context *ctx,
2929 const struct gl_sampler_object *samp,
2930 const struct gl_texture_object *tObj,
2931 GLuint n, const GLfloat texcoord[][4],
2932 const GLfloat lambda[], GLfloat rgba[][4])
2933 {
2934 GLuint i;
2935 for (i = 0; i < n; i++) {
2936 GLint level = nearest_mipmap_level(tObj, lambda[i]);
2937 sample_2d_array_nearest(ctx, samp, tObj->Image[0][level], texcoord[i],
2938 rgba[i]);
2939 }
2940 }
2941
2942
2943 static void
sample_2d_array_linear_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2944 sample_2d_array_linear_mipmap_nearest(struct gl_context *ctx,
2945 const struct gl_sampler_object *samp,
2946 const struct gl_texture_object *tObj,
2947 GLuint n, const GLfloat texcoord[][4],
2948 const GLfloat lambda[], GLfloat rgba[][4])
2949 {
2950 GLuint i;
2951 assert(lambda != NULL);
2952 for (i = 0; i < n; i++) {
2953 GLint level = nearest_mipmap_level(tObj, lambda[i]);
2954 sample_2d_array_linear(ctx, samp, tObj->Image[0][level],
2955 texcoord[i], rgba[i]);
2956 }
2957 }
2958
2959
2960 static void
sample_2d_array_nearest_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2961 sample_2d_array_nearest_mipmap_linear(struct gl_context *ctx,
2962 const struct gl_sampler_object *samp,
2963 const struct gl_texture_object *tObj,
2964 GLuint n, const GLfloat texcoord[][4],
2965 const GLfloat lambda[], GLfloat rgba[][4])
2966 {
2967 GLuint i;
2968 assert(lambda != NULL);
2969 for (i = 0; i < n; i++) {
2970 GLint level = linear_mipmap_level(tObj, lambda[i]);
2971 if (level >= tObj->_MaxLevel) {
2972 sample_2d_array_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
2973 texcoord[i], rgba[i]);
2974 }
2975 else {
2976 GLfloat t0[4], t1[4]; /* texels */
2977 const GLfloat f = FRAC(lambda[i]);
2978 sample_2d_array_nearest(ctx, samp, tObj->Image[0][level ],
2979 texcoord[i], t0);
2980 sample_2d_array_nearest(ctx, samp, tObj->Image[0][level+1],
2981 texcoord[i], t1);
2982 lerp_rgba(rgba[i], f, t0, t1);
2983 }
2984 }
2985 }
2986
2987
2988 static void
sample_2d_array_linear_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])2989 sample_2d_array_linear_mipmap_linear(struct gl_context *ctx,
2990 const struct gl_sampler_object *samp,
2991 const struct gl_texture_object *tObj,
2992 GLuint n, const GLfloat texcoord[][4],
2993 const GLfloat lambda[], GLfloat rgba[][4])
2994 {
2995 GLuint i;
2996 assert(lambda != NULL);
2997 for (i = 0; i < n; i++) {
2998 GLint level = linear_mipmap_level(tObj, lambda[i]);
2999 if (level >= tObj->_MaxLevel) {
3000 sample_2d_array_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
3001 texcoord[i], rgba[i]);
3002 }
3003 else {
3004 GLfloat t0[4], t1[4]; /* texels */
3005 const GLfloat f = FRAC(lambda[i]);
3006 sample_2d_array_linear(ctx, samp, tObj->Image[0][level ],
3007 texcoord[i], t0);
3008 sample_2d_array_linear(ctx, samp, tObj->Image[0][level+1],
3009 texcoord[i], t1);
3010 lerp_rgba(rgba[i], f, t0, t1);
3011 }
3012 }
3013 }
3014
3015
3016 /** Sample 2D Array texture, nearest filtering for both min/magnification */
3017 static void
sample_nearest_2d_array(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])3018 sample_nearest_2d_array(struct gl_context *ctx,
3019 const struct gl_sampler_object *samp,
3020 const struct gl_texture_object *tObj, GLuint n,
3021 const GLfloat texcoords[][4], const GLfloat lambda[],
3022 GLfloat rgba[][4])
3023 {
3024 GLuint i;
3025 const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
3026 (void) lambda;
3027 for (i = 0; i < n; i++) {
3028 sample_2d_array_nearest(ctx, samp, image, texcoords[i], rgba[i]);
3029 }
3030 }
3031
3032
3033
3034 /** Sample 2D Array texture, linear filtering for both min/magnification */
3035 static void
sample_linear_2d_array(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])3036 sample_linear_2d_array(struct gl_context *ctx,
3037 const struct gl_sampler_object *samp,
3038 const struct gl_texture_object *tObj, GLuint n,
3039 const GLfloat texcoords[][4],
3040 const GLfloat lambda[], GLfloat rgba[][4])
3041 {
3042 GLuint i;
3043 const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
3044 (void) lambda;
3045 for (i = 0; i < n; i++) {
3046 sample_2d_array_linear(ctx, samp, image, texcoords[i], rgba[i]);
3047 }
3048 }
3049
3050
3051 /** Sample 2D Array texture, using lambda to choose between min/magnification */
3052 static void
sample_lambda_2d_array(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])3053 sample_lambda_2d_array(struct gl_context *ctx,
3054 const struct gl_sampler_object *samp,
3055 const struct gl_texture_object *tObj, GLuint n,
3056 const GLfloat texcoords[][4], const GLfloat lambda[],
3057 GLfloat rgba[][4])
3058 {
3059 GLuint minStart, minEnd; /* texels with minification */
3060 GLuint magStart, magEnd; /* texels with magnification */
3061 GLuint i;
3062
3063 assert(lambda != NULL);
3064 compute_min_mag_ranges(samp, n, lambda,
3065 &minStart, &minEnd, &magStart, &magEnd);
3066
3067 if (minStart < minEnd) {
3068 /* do the minified texels */
3069 GLuint m = minEnd - minStart;
3070 switch (samp->MinFilter) {
3071 case GL_NEAREST:
3072 for (i = minStart; i < minEnd; i++)
3073 sample_2d_array_nearest(ctx, samp, _mesa_base_tex_image(tObj),
3074 texcoords[i], rgba[i]);
3075 break;
3076 case GL_LINEAR:
3077 for (i = minStart; i < minEnd; i++)
3078 sample_2d_array_linear(ctx, samp, _mesa_base_tex_image(tObj),
3079 texcoords[i], rgba[i]);
3080 break;
3081 case GL_NEAREST_MIPMAP_NEAREST:
3082 sample_2d_array_nearest_mipmap_nearest(ctx, samp, tObj, m,
3083 texcoords + minStart,
3084 lambda + minStart,
3085 rgba + minStart);
3086 break;
3087 case GL_LINEAR_MIPMAP_NEAREST:
3088 sample_2d_array_linear_mipmap_nearest(ctx, samp, tObj, m,
3089 texcoords + minStart,
3090 lambda + minStart,
3091 rgba + minStart);
3092 break;
3093 case GL_NEAREST_MIPMAP_LINEAR:
3094 sample_2d_array_nearest_mipmap_linear(ctx, samp, tObj, m,
3095 texcoords + minStart,
3096 lambda + minStart,
3097 rgba + minStart);
3098 break;
3099 case GL_LINEAR_MIPMAP_LINEAR:
3100 sample_2d_array_linear_mipmap_linear(ctx, samp, tObj, m,
3101 texcoords + minStart,
3102 lambda + minStart,
3103 rgba + minStart);
3104 break;
3105 default:
3106 _mesa_problem(ctx, "Bad min filter in sample_2d_array_texture");
3107 return;
3108 }
3109 }
3110
3111 if (magStart < magEnd) {
3112 /* do the magnified texels */
3113 switch (samp->MagFilter) {
3114 case GL_NEAREST:
3115 for (i = magStart; i < magEnd; i++)
3116 sample_2d_array_nearest(ctx, samp, _mesa_base_tex_image(tObj),
3117 texcoords[i], rgba[i]);
3118 break;
3119 case GL_LINEAR:
3120 for (i = magStart; i < magEnd; i++)
3121 sample_2d_array_linear(ctx, samp, _mesa_base_tex_image(tObj),
3122 texcoords[i], rgba[i]);
3123 break;
3124 default:
3125 _mesa_problem(ctx, "Bad mag filter in sample_2d_array_texture");
3126 return;
3127 }
3128 }
3129 }
3130
3131
3132
3133
3134 /**********************************************************************/
3135 /* 1D Texture Array Sampling Functions */
3136 /**********************************************************************/
3137
3138 /**
3139 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
3140 */
3141 static void
sample_1d_array_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[4])3142 sample_1d_array_nearest(struct gl_context *ctx,
3143 const struct gl_sampler_object *samp,
3144 const struct gl_texture_image *img,
3145 const GLfloat texcoord[4],
3146 GLfloat rgba[4])
3147 {
3148 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
3149 const GLint width = img->Width2; /* without border, power of two */
3150 const GLint height = img->Height;
3151 GLint i;
3152 GLint array;
3153 (void) ctx;
3154
3155 i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
3156 array = tex_array_slice(texcoord[1], height);
3157
3158 if (i < 0 || i >= (GLint) img->Width ||
3159 array < 0 || array >= (GLint) img->Height) {
3160 /* Need this test for GL_CLAMP_TO_BORDER mode */
3161 get_border_color(samp, img, rgba);
3162 }
3163 else {
3164 swImg->FetchTexel(swImg, i, array, 0, rgba);
3165 }
3166 }
3167
3168
3169 /**
3170 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
3171 */
3172 static void
sample_1d_array_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_image * img,const GLfloat texcoord[4],GLfloat rgba[4])3173 sample_1d_array_linear(struct gl_context *ctx,
3174 const struct gl_sampler_object *samp,
3175 const struct gl_texture_image *img,
3176 const GLfloat texcoord[4],
3177 GLfloat rgba[4])
3178 {
3179 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
3180 const GLint width = img->Width2;
3181 const GLint height = img->Height;
3182 GLint i0, i1;
3183 GLint array;
3184 GLbitfield useBorderColor = 0x0;
3185 GLfloat a;
3186 GLfloat t0[4], t1[4];
3187
3188 linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a);
3189 array = tex_array_slice(texcoord[1], height);
3190
3191 if (img->Border) {
3192 i0 += img->Border;
3193 i1 += img->Border;
3194 }
3195 else {
3196 /* check if sampling texture border color */
3197 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
3198 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
3199 }
3200
3201 if (array < 0 || array >= height) useBorderColor |= K0BIT;
3202
3203 /* Fetch texels */
3204 if (useBorderColor & (I0BIT | K0BIT)) {
3205 get_border_color(samp, img, t0);
3206 }
3207 else {
3208 swImg->FetchTexel(swImg, i0, array, 0, t0);
3209 }
3210 if (useBorderColor & (I1BIT | K0BIT)) {
3211 get_border_color(samp, img, t1);
3212 }
3213 else {
3214 swImg->FetchTexel(swImg, i1, array, 0, t1);
3215 }
3216
3217 /* bilinear interpolation of samples */
3218 lerp_rgba(rgba, a, t0, t1);
3219 }
3220
3221
3222 static void
sample_1d_array_nearest_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])3223 sample_1d_array_nearest_mipmap_nearest(struct gl_context *ctx,
3224 const struct gl_sampler_object *samp,
3225 const struct gl_texture_object *tObj,
3226 GLuint n, const GLfloat texcoord[][4],
3227 const GLfloat lambda[], GLfloat rgba[][4])
3228 {
3229 GLuint i;
3230 for (i = 0; i < n; i++) {
3231 GLint level = nearest_mipmap_level(tObj, lambda[i]);
3232 sample_1d_array_nearest(ctx, samp, tObj->Image[0][level], texcoord[i],
3233 rgba[i]);
3234 }
3235 }
3236
3237
3238 static void
sample_1d_array_linear_mipmap_nearest(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])3239 sample_1d_array_linear_mipmap_nearest(struct gl_context *ctx,
3240 const struct gl_sampler_object *samp,
3241 const struct gl_texture_object *tObj,
3242 GLuint n, const GLfloat texcoord[][4],
3243 const GLfloat lambda[], GLfloat rgba[][4])
3244 {
3245 GLuint i;
3246 assert(lambda != NULL);
3247 for (i = 0; i < n; i++) {
3248 GLint level = nearest_mipmap_level(tObj, lambda[i]);
3249 sample_1d_array_linear(ctx, samp, tObj->Image[0][level],
3250 texcoord[i], rgba[i]);
3251 }
3252 }
3253
3254
3255 static void
sample_1d_array_nearest_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])3256 sample_1d_array_nearest_mipmap_linear(struct gl_context *ctx,
3257 const struct gl_sampler_object *samp,
3258 const struct gl_texture_object *tObj,
3259 GLuint n, const GLfloat texcoord[][4],
3260 const GLfloat lambda[], GLfloat rgba[][4])
3261 {
3262 GLuint i;
3263 assert(lambda != NULL);
3264 for (i = 0; i < n; i++) {
3265 GLint level = linear_mipmap_level(tObj, lambda[i]);
3266 if (level >= tObj->_MaxLevel) {
3267 sample_1d_array_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
3268 texcoord[i], rgba[i]);
3269 }
3270 else {
3271 GLfloat t0[4], t1[4]; /* texels */
3272 const GLfloat f = FRAC(lambda[i]);
3273 sample_1d_array_nearest(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
3274 sample_1d_array_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
3275 lerp_rgba(rgba[i], f, t0, t1);
3276 }
3277 }
3278 }
3279
3280
3281 static void
sample_1d_array_linear_mipmap_linear(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoord[][4],const GLfloat lambda[],GLfloat rgba[][4])3282 sample_1d_array_linear_mipmap_linear(struct gl_context *ctx,
3283 const struct gl_sampler_object *samp,
3284 const struct gl_texture_object *tObj,
3285 GLuint n, const GLfloat texcoord[][4],
3286 const GLfloat lambda[], GLfloat rgba[][4])
3287 {
3288 GLuint i;
3289 assert(lambda != NULL);
3290 for (i = 0; i < n; i++) {
3291 GLint level = linear_mipmap_level(tObj, lambda[i]);
3292 if (level >= tObj->_MaxLevel) {
3293 sample_1d_array_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
3294 texcoord[i], rgba[i]);
3295 }
3296 else {
3297 GLfloat t0[4], t1[4]; /* texels */
3298 const GLfloat f = FRAC(lambda[i]);
3299 sample_1d_array_linear(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
3300 sample_1d_array_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
3301 lerp_rgba(rgba[i], f, t0, t1);
3302 }
3303 }
3304 }
3305
3306
3307 /** Sample 1D Array texture, nearest filtering for both min/magnification */
3308 static void
sample_nearest_1d_array(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])3309 sample_nearest_1d_array(struct gl_context *ctx,
3310 const struct gl_sampler_object *samp,
3311 const struct gl_texture_object *tObj, GLuint n,
3312 const GLfloat texcoords[][4], const GLfloat lambda[],
3313 GLfloat rgba[][4])
3314 {
3315 GLuint i;
3316 const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
3317 (void) lambda;
3318 for (i = 0; i < n; i++) {
3319 sample_1d_array_nearest(ctx, samp, image, texcoords[i], rgba[i]);
3320 }
3321 }
3322
3323
3324 /** Sample 1D Array texture, linear filtering for both min/magnification */
3325 static void
sample_linear_1d_array(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])3326 sample_linear_1d_array(struct gl_context *ctx,
3327 const struct gl_sampler_object *samp,
3328 const struct gl_texture_object *tObj, GLuint n,
3329 const GLfloat texcoords[][4],
3330 const GLfloat lambda[], GLfloat rgba[][4])
3331 {
3332 GLuint i;
3333 const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
3334 (void) lambda;
3335 for (i = 0; i < n; i++) {
3336 sample_1d_array_linear(ctx, samp, image, texcoords[i], rgba[i]);
3337 }
3338 }
3339
3340
3341 /** Sample 1D Array texture, using lambda to choose between min/magnification */
3342 static void
sample_lambda_1d_array(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])3343 sample_lambda_1d_array(struct gl_context *ctx,
3344 const struct gl_sampler_object *samp,
3345 const struct gl_texture_object *tObj, GLuint n,
3346 const GLfloat texcoords[][4], const GLfloat lambda[],
3347 GLfloat rgba[][4])
3348 {
3349 GLuint minStart, minEnd; /* texels with minification */
3350 GLuint magStart, magEnd; /* texels with magnification */
3351 GLuint i;
3352
3353 assert(lambda != NULL);
3354 compute_min_mag_ranges(samp, n, lambda,
3355 &minStart, &minEnd, &magStart, &magEnd);
3356
3357 if (minStart < minEnd) {
3358 /* do the minified texels */
3359 GLuint m = minEnd - minStart;
3360 switch (samp->MinFilter) {
3361 case GL_NEAREST:
3362 for (i = minStart; i < minEnd; i++)
3363 sample_1d_array_nearest(ctx, samp, _mesa_base_tex_image(tObj),
3364 texcoords[i], rgba[i]);
3365 break;
3366 case GL_LINEAR:
3367 for (i = minStart; i < minEnd; i++)
3368 sample_1d_array_linear(ctx, samp, _mesa_base_tex_image(tObj),
3369 texcoords[i], rgba[i]);
3370 break;
3371 case GL_NEAREST_MIPMAP_NEAREST:
3372 sample_1d_array_nearest_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
3373 lambda + minStart, rgba + minStart);
3374 break;
3375 case GL_LINEAR_MIPMAP_NEAREST:
3376 sample_1d_array_linear_mipmap_nearest(ctx, samp, tObj, m,
3377 texcoords + minStart,
3378 lambda + minStart,
3379 rgba + minStart);
3380 break;
3381 case GL_NEAREST_MIPMAP_LINEAR:
3382 sample_1d_array_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
3383 lambda + minStart, rgba + minStart);
3384 break;
3385 case GL_LINEAR_MIPMAP_LINEAR:
3386 sample_1d_array_linear_mipmap_linear(ctx, samp, tObj, m,
3387 texcoords + minStart,
3388 lambda + minStart,
3389 rgba + minStart);
3390 break;
3391 default:
3392 _mesa_problem(ctx, "Bad min filter in sample_1d_array_texture");
3393 return;
3394 }
3395 }
3396
3397 if (magStart < magEnd) {
3398 /* do the magnified texels */
3399 switch (samp->MagFilter) {
3400 case GL_NEAREST:
3401 for (i = magStart; i < magEnd; i++)
3402 sample_1d_array_nearest(ctx, samp, _mesa_base_tex_image(tObj),
3403 texcoords[i], rgba[i]);
3404 break;
3405 case GL_LINEAR:
3406 for (i = magStart; i < magEnd; i++)
3407 sample_1d_array_linear(ctx, samp, _mesa_base_tex_image(tObj),
3408 texcoords[i], rgba[i]);
3409 break;
3410 default:
3411 _mesa_problem(ctx, "Bad mag filter in sample_1d_array_texture");
3412 return;
3413 }
3414 }
3415 }
3416
3417
3418 /**
3419 * Compare texcoord against depth sample. Return 1.0 or 0.0 value.
3420 */
3421 static GLfloat
shadow_compare(GLenum function,GLfloat coord,GLfloat depthSample)3422 shadow_compare(GLenum function, GLfloat coord, GLfloat depthSample)
3423 {
3424 switch (function) {
3425 case GL_LEQUAL:
3426 return (coord <= depthSample) ? 1.0F : 0.0F;
3427 case GL_GEQUAL:
3428 return (coord >= depthSample) ? 1.0F : 0.0F;
3429 case GL_LESS:
3430 return (coord < depthSample) ? 1.0F : 0.0F;
3431 case GL_GREATER:
3432 return (coord > depthSample) ? 1.0F : 0.0F;
3433 case GL_EQUAL:
3434 return (coord == depthSample) ? 1.0F : 0.0F;
3435 case GL_NOTEQUAL:
3436 return (coord != depthSample) ? 1.0F : 0.0F;
3437 case GL_ALWAYS:
3438 return 1.0F;
3439 case GL_NEVER:
3440 return 0.0F;
3441 case GL_NONE:
3442 return depthSample;
3443 default:
3444 _mesa_problem(NULL, "Bad compare func in shadow_compare");
3445 return 0.0F;
3446 }
3447 }
3448
3449
3450 /**
3451 * Compare texcoord against four depth samples.
3452 */
3453 static GLfloat
shadow_compare4(GLenum function,GLfloat coord,GLfloat depth00,GLfloat depth01,GLfloat depth10,GLfloat depth11,GLfloat wi,GLfloat wj)3454 shadow_compare4(GLenum function, GLfloat coord,
3455 GLfloat depth00, GLfloat depth01,
3456 GLfloat depth10, GLfloat depth11,
3457 GLfloat wi, GLfloat wj)
3458 {
3459 const GLfloat d = 0.25F;
3460 GLfloat luminance = 1.0F;
3461
3462 switch (function) {
3463 case GL_LEQUAL:
3464 if (coord > depth00) luminance -= d;
3465 if (coord > depth01) luminance -= d;
3466 if (coord > depth10) luminance -= d;
3467 if (coord > depth11) luminance -= d;
3468 return luminance;
3469 case GL_GEQUAL:
3470 if (coord < depth00) luminance -= d;
3471 if (coord < depth01) luminance -= d;
3472 if (coord < depth10) luminance -= d;
3473 if (coord < depth11) luminance -= d;
3474 return luminance;
3475 case GL_LESS:
3476 if (coord >= depth00) luminance -= d;
3477 if (coord >= depth01) luminance -= d;
3478 if (coord >= depth10) luminance -= d;
3479 if (coord >= depth11) luminance -= d;
3480 return luminance;
3481 case GL_GREATER:
3482 if (coord <= depth00) luminance -= d;
3483 if (coord <= depth01) luminance -= d;
3484 if (coord <= depth10) luminance -= d;
3485 if (coord <= depth11) luminance -= d;
3486 return luminance;
3487 case GL_EQUAL:
3488 if (coord != depth00) luminance -= d;
3489 if (coord != depth01) luminance -= d;
3490 if (coord != depth10) luminance -= d;
3491 if (coord != depth11) luminance -= d;
3492 return luminance;
3493 case GL_NOTEQUAL:
3494 if (coord == depth00) luminance -= d;
3495 if (coord == depth01) luminance -= d;
3496 if (coord == depth10) luminance -= d;
3497 if (coord == depth11) luminance -= d;
3498 return luminance;
3499 case GL_ALWAYS:
3500 return 1.0F;
3501 case GL_NEVER:
3502 return 0.0F;
3503 case GL_NONE:
3504 /* ordinary bilinear filtering */
3505 return lerp_2d(wi, wj, depth00, depth10, depth01, depth11);
3506 default:
3507 _mesa_problem(NULL, "Bad compare func in sample_compare4");
3508 return 0.0F;
3509 }
3510 }
3511
3512
3513 /**
3514 * Choose the mipmap level to use when sampling from a depth texture.
3515 */
3516 static int
choose_depth_texture_level(const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLfloat lambda)3517 choose_depth_texture_level(const struct gl_sampler_object *samp,
3518 const struct gl_texture_object *tObj, GLfloat lambda)
3519 {
3520 GLint level;
3521
3522 if (samp->MinFilter == GL_NEAREST || samp->MinFilter == GL_LINEAR) {
3523 /* no mipmapping - use base level */
3524 level = tObj->BaseLevel;
3525 }
3526 else {
3527 /* choose mipmap level */
3528 lambda = CLAMP(lambda, samp->MinLod, samp->MaxLod);
3529 level = (GLint) lambda;
3530 level = CLAMP(level, tObj->BaseLevel, tObj->_MaxLevel);
3531 }
3532
3533 return level;
3534 }
3535
3536
3537 /**
3538 * Sample a shadow/depth texture. This function is incomplete. It doesn't
3539 * check for minification vs. magnification, etc.
3540 */
3541 static void
sample_depth_texture(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat texel[][4])3542 sample_depth_texture( struct gl_context *ctx,
3543 const struct gl_sampler_object *samp,
3544 const struct gl_texture_object *tObj, GLuint n,
3545 const GLfloat texcoords[][4], const GLfloat lambda[],
3546 GLfloat texel[][4] )
3547 {
3548 const GLint level = choose_depth_texture_level(samp, tObj, lambda[0]);
3549 const struct gl_texture_image *img = tObj->Image[0][level];
3550 const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
3551 const GLint width = img->Width;
3552 const GLint height = img->Height;
3553 const GLint depth = img->Depth;
3554 const GLuint compare_coord = (tObj->Target == GL_TEXTURE_2D_ARRAY_EXT)
3555 ? 3 : 2;
3556 GLenum function;
3557 GLfloat result;
3558
3559 assert(img->_BaseFormat == GL_DEPTH_COMPONENT ||
3560 img->_BaseFormat == GL_DEPTH_STENCIL_EXT);
3561
3562 assert(tObj->Target == GL_TEXTURE_1D ||
3563 tObj->Target == GL_TEXTURE_2D ||
3564 tObj->Target == GL_TEXTURE_RECTANGLE_NV ||
3565 tObj->Target == GL_TEXTURE_1D_ARRAY_EXT ||
3566 tObj->Target == GL_TEXTURE_2D_ARRAY_EXT ||
3567 tObj->Target == GL_TEXTURE_CUBE_MAP);
3568
3569 /* XXXX if samp->MinFilter != samp->MagFilter, we're ignoring lambda */
3570
3571 function = (samp->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) ?
3572 samp->CompareFunc : GL_NONE;
3573
3574 if (samp->MagFilter == GL_NEAREST) {
3575 GLuint i;
3576 for (i = 0; i < n; i++) {
3577 GLfloat depthSample, depthRef;
3578 GLint col, row, slice;
3579
3580 nearest_texcoord(samp, tObj, level, texcoords[i], &col, &row, &slice);
3581
3582 if (col >= 0 && row >= 0 && col < width && row < height &&
3583 slice >= 0 && slice < depth) {
3584 swImg->FetchTexel(swImg, col, row, slice, &depthSample);
3585 }
3586 else {
3587 depthSample = samp->BorderColor.f[0];
3588 }
3589
3590 depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F);
3591
3592 result = shadow_compare(function, depthRef, depthSample);
3593
3594 apply_depth_mode(tObj->DepthMode, result, texel[i]);
3595 }
3596 }
3597 else {
3598 GLuint i;
3599 assert(samp->MagFilter == GL_LINEAR);
3600 for (i = 0; i < n; i++) {
3601 GLfloat depth00, depth01, depth10, depth11, depthRef;
3602 GLint i0, i1, j0, j1;
3603 GLint slice;
3604 GLfloat wi, wj;
3605 GLuint useBorderTexel;
3606
3607 linear_texcoord(samp, tObj, level, texcoords[i], &i0, &i1, &j0, &j1, &slice,
3608 &wi, &wj);
3609
3610 useBorderTexel = 0;
3611 if (img->Border) {
3612 i0 += img->Border;
3613 i1 += img->Border;
3614 if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) {
3615 j0 += img->Border;
3616 j1 += img->Border;
3617 }
3618 }
3619 else {
3620 if (i0 < 0 || i0 >= (GLint) width) useBorderTexel |= I0BIT;
3621 if (i1 < 0 || i1 >= (GLint) width) useBorderTexel |= I1BIT;
3622 if (j0 < 0 || j0 >= (GLint) height) useBorderTexel |= J0BIT;
3623 if (j1 < 0 || j1 >= (GLint) height) useBorderTexel |= J1BIT;
3624 }
3625
3626 if (slice < 0 || slice >= (GLint) depth) {
3627 depth00 = samp->BorderColor.f[0];
3628 depth01 = samp->BorderColor.f[0];
3629 depth10 = samp->BorderColor.f[0];
3630 depth11 = samp->BorderColor.f[0];
3631 }
3632 else {
3633 /* get four depth samples from the texture */
3634 if (useBorderTexel & (I0BIT | J0BIT)) {
3635 depth00 = samp->BorderColor.f[0];
3636 }
3637 else {
3638 swImg->FetchTexel(swImg, i0, j0, slice, &depth00);
3639 }
3640 if (useBorderTexel & (I1BIT | J0BIT)) {
3641 depth10 = samp->BorderColor.f[0];
3642 }
3643 else {
3644 swImg->FetchTexel(swImg, i1, j0, slice, &depth10);
3645 }
3646
3647 if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) {
3648 if (useBorderTexel & (I0BIT | J1BIT)) {
3649 depth01 = samp->BorderColor.f[0];
3650 }
3651 else {
3652 swImg->FetchTexel(swImg, i0, j1, slice, &depth01);
3653 }
3654 if (useBorderTexel & (I1BIT | J1BIT)) {
3655 depth11 = samp->BorderColor.f[0];
3656 }
3657 else {
3658 swImg->FetchTexel(swImg, i1, j1, slice, &depth11);
3659 }
3660 }
3661 else {
3662 depth01 = depth00;
3663 depth11 = depth10;
3664 }
3665 }
3666
3667 depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F);
3668
3669 result = shadow_compare4(function, depthRef,
3670 depth00, depth01, depth10, depth11,
3671 wi, wj);
3672
3673 apply_depth_mode(tObj->DepthMode, result, texel[i]);
3674 } /* for */
3675 } /* if filter */
3676 }
3677
3678
3679 /**
3680 * We use this function when a texture object is in an "incomplete" state.
3681 * When a fragment program attempts to sample an incomplete texture we
3682 * return black (see issue 23 in GL_ARB_fragment_program spec).
3683 * Note: fragment programs don't observe the texture enable/disable flags.
3684 */
3685 static void
null_sample_func(struct gl_context * ctx,const struct gl_sampler_object * samp,const struct gl_texture_object * tObj,GLuint n,const GLfloat texcoords[][4],const GLfloat lambda[],GLfloat rgba[][4])3686 null_sample_func( struct gl_context *ctx,
3687 const struct gl_sampler_object *samp,
3688 const struct gl_texture_object *tObj, GLuint n,
3689 const GLfloat texcoords[][4], const GLfloat lambda[],
3690 GLfloat rgba[][4])
3691 {
3692 GLuint i;
3693 (void) ctx;
3694 (void) tObj;
3695 (void) texcoords;
3696 (void) lambda;
3697 (void) samp;
3698 for (i = 0; i < n; i++) {
3699 rgba[i][RCOMP] = 0;
3700 rgba[i][GCOMP] = 0;
3701 rgba[i][BCOMP] = 0;
3702 rgba[i][ACOMP] = 1.0;
3703 }
3704 }
3705
3706
3707 /**
3708 * Choose the texture sampling function for the given texture object.
3709 */
3710 texture_sample_func
_swrast_choose_texture_sample_func(struct gl_context * ctx,const struct gl_texture_object * t,const struct gl_sampler_object * sampler)3711 _swrast_choose_texture_sample_func( struct gl_context *ctx,
3712 const struct gl_texture_object *t,
3713 const struct gl_sampler_object *sampler)
3714 {
3715 if (!t || !_mesa_is_texture_complete(t, sampler,
3716 ctx->Const.ForceIntegerTexNearest)) {
3717 return null_sample_func;
3718 }
3719 else {
3720 const GLboolean needLambda =
3721 (GLboolean) (sampler->MinFilter != sampler->MagFilter);
3722
3723 switch (t->Target) {
3724 case GL_TEXTURE_1D:
3725 if (is_depth_texture(t)) {
3726 return sample_depth_texture;
3727 }
3728 else if (needLambda) {
3729 return sample_lambda_1d;
3730 }
3731 else if (sampler->MinFilter == GL_LINEAR) {
3732 return sample_linear_1d;
3733 }
3734 else {
3735 assert(sampler->MinFilter == GL_NEAREST);
3736 return sample_nearest_1d;
3737 }
3738 case GL_TEXTURE_2D:
3739 if (is_depth_texture(t)) {
3740 return sample_depth_texture;
3741 }
3742 else if (needLambda) {
3743 /* Anisotropic filtering extension. Activated only if mipmaps are used */
3744 if (sampler->MaxAnisotropy > 1.0F &&
3745 sampler->MinFilter == GL_LINEAR_MIPMAP_LINEAR) {
3746 return sample_lambda_2d_aniso;
3747 }
3748 return sample_lambda_2d;
3749 }
3750 else if (sampler->MinFilter == GL_LINEAR) {
3751 return sample_linear_2d;
3752 }
3753 else {
3754 /* check for a few optimized cases */
3755 const struct gl_texture_image *img = _mesa_base_tex_image(t);
3756 const struct swrast_texture_image *swImg =
3757 swrast_texture_image_const(img);
3758 texture_sample_func func;
3759
3760 assert(sampler->MinFilter == GL_NEAREST);
3761 func = &sample_nearest_2d;
3762 if (sampler->WrapS == GL_REPEAT &&
3763 sampler->WrapT == GL_REPEAT &&
3764 swImg->_IsPowerOfTwo &&
3765 img->Border == 0) {
3766 if (img->TexFormat == MESA_FORMAT_BGR_UNORM8)
3767 func = &opt_sample_rgb_2d;
3768 else if (img->TexFormat == MESA_FORMAT_A8B8G8R8_UNORM)
3769 func = &opt_sample_rgba_2d;
3770 }
3771
3772 return func;
3773 }
3774 case GL_TEXTURE_3D:
3775 if (needLambda) {
3776 return sample_lambda_3d;
3777 }
3778 else if (sampler->MinFilter == GL_LINEAR) {
3779 return sample_linear_3d;
3780 }
3781 else {
3782 assert(sampler->MinFilter == GL_NEAREST);
3783 return sample_nearest_3d;
3784 }
3785 case GL_TEXTURE_CUBE_MAP:
3786 if (needLambda) {
3787 return sample_lambda_cube;
3788 }
3789 else if (sampler->MinFilter == GL_LINEAR) {
3790 return sample_linear_cube;
3791 }
3792 else {
3793 assert(sampler->MinFilter == GL_NEAREST);
3794 return sample_nearest_cube;
3795 }
3796 case GL_TEXTURE_RECTANGLE_NV:
3797 if (is_depth_texture(t)) {
3798 return sample_depth_texture;
3799 }
3800 else if (needLambda) {
3801 return sample_lambda_rect;
3802 }
3803 else if (sampler->MinFilter == GL_LINEAR) {
3804 return sample_linear_rect;
3805 }
3806 else {
3807 assert(sampler->MinFilter == GL_NEAREST);
3808 return sample_nearest_rect;
3809 }
3810 case GL_TEXTURE_1D_ARRAY_EXT:
3811 if (is_depth_texture(t)) {
3812 return sample_depth_texture;
3813 }
3814 else if (needLambda) {
3815 return sample_lambda_1d_array;
3816 }
3817 else if (sampler->MinFilter == GL_LINEAR) {
3818 return sample_linear_1d_array;
3819 }
3820 else {
3821 assert(sampler->MinFilter == GL_NEAREST);
3822 return sample_nearest_1d_array;
3823 }
3824 case GL_TEXTURE_2D_ARRAY_EXT:
3825 if (is_depth_texture(t)) {
3826 return sample_depth_texture;
3827 }
3828 else if (needLambda) {
3829 return sample_lambda_2d_array;
3830 }
3831 else if (sampler->MinFilter == GL_LINEAR) {
3832 return sample_linear_2d_array;
3833 }
3834 else {
3835 assert(sampler->MinFilter == GL_NEAREST);
3836 return sample_nearest_2d_array;
3837 }
3838 default:
3839 _mesa_problem(ctx,
3840 "invalid target in _swrast_choose_texture_sample_func");
3841 return null_sample_func;
3842 }
3843 }
3844 }
3845