Subversion Repositories Kolibri OS

Rev

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

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