Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

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