Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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