Subversion Repositories shark

Rev

Rev 55 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
55 pj 1
/* $Id: texobj.c,v 1.1 2003-02-28 11:42:05 pj Exp $ */
2
 
3
/*
4
 * Mesa 3-D graphics library
5
 * Version:  4.1
6
 *
7
 * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a
10
 * copy of this software and associated documentation files (the "Software"),
11
 * to deal in the Software without restriction, including without limitation
12
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13
 * and/or sell copies of the Software, and to permit persons to whom the
14
 * Software is furnished to do so, subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included
17
 * in all copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22
 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 */
26
 
27
#include "glheader.h"
28
#include "colortab.h"
29
#include "context.h"
30
#include "enums.h"
31
#include "hash.h"
32
#include "imports.h"
33
#include "macros.h"
34
#include "teximage.h"
35
#include "texstate.h"
36
#include "texobj.h"
37
#include "mtypes.h"
38
 
39
 
40
/*
41
 * Allocate a new texture object and add it to the linked list of texture
42
 * objects.  If name>0 then also insert the new texture object into the hash
43
 * table.
44
 * Input:  shared - the shared GL state structure to contain the texture object
45
 *         name - integer name for the texture object
46
 *         target - either GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D,
47
 *                  GL_TEXTURE_CUBE_MAP_ARB or GL_TEXTURE_RECTANGLE_NV
48
 *                      zero is ok for the sake of GenTextures()
49
 * Return:  pointer to new texture object
50
 */
51
struct gl_texture_object *
52
_mesa_alloc_texture_object( struct gl_shared_state *shared,
53
                            GLuint name, GLenum target )
54
{
55
   struct gl_texture_object *obj;
56
 
57
   ASSERT(target == 0 ||
58
          target == GL_TEXTURE_1D ||
59
          target == GL_TEXTURE_2D ||
60
          target == GL_TEXTURE_3D ||
61
          target == GL_TEXTURE_CUBE_MAP_ARB ||
62
          target == GL_TEXTURE_RECTANGLE_NV);
63
 
64
   obj = CALLOC_STRUCT(gl_texture_object);
65
 
66
   if (obj) {
67
      /* init the non-zero fields */
68
      _glthread_INIT_MUTEX(obj->Mutex);
69
      obj->RefCount = 1;
70
      obj->Name = name;
71
      obj->Target = target;
72
      obj->Priority = 1.0F;
73
      if (target == GL_TEXTURE_RECTANGLE_NV) {
74
         obj->WrapS = GL_CLAMP_TO_EDGE;
75
         obj->WrapT = GL_CLAMP_TO_EDGE;
76
         obj->WrapR = GL_CLAMP_TO_EDGE;
77
         obj->MinFilter = GL_LINEAR;
78
      }
79
      else {
80
         obj->WrapS = GL_REPEAT;
81
         obj->WrapT = GL_REPEAT;
82
         obj->WrapR = GL_REPEAT;
83
         obj->MinFilter = GL_NEAREST_MIPMAP_LINEAR;
84
      }
85
      obj->MagFilter = GL_LINEAR;
86
      obj->MinLod = -1000.0;
87
      obj->MaxLod = 1000.0;
88
      obj->BaseLevel = 0;
89
      obj->MaxLevel = 1000;
90
      obj->MaxAnisotropy = 1.0;
91
      obj->CompareFlag = GL_FALSE;                      /* SGIX_shadow */
92
      obj->CompareOperator = GL_TEXTURE_LEQUAL_R_SGIX;  /* SGIX_shadow */
93
      obj->CompareMode = GL_LUMINANCE;    /* ARB_shadow */
94
      obj->CompareFunc = GL_LEQUAL;       /* ARB_shadow */
95
      obj->DepthMode = GL_LUMINANCE;      /* ARB_depth_texture */
96
      obj->ShadowAmbient = 0.0F;          /* ARB/SGIX_shadow_ambient */
97
      _mesa_init_colortable(&obj->Palette);
98
 
99
      /* insert into linked list */
100
      if (shared) {
101
         _glthread_LOCK_MUTEX(shared->Mutex);
102
         obj->Next = shared->TexObjectList;
103
         shared->TexObjectList = obj;
104
         _glthread_UNLOCK_MUTEX(shared->Mutex);
105
      }
106
 
107
      if (name > 0) {
108
         /* insert into hash table */
109
         _mesa_HashInsert(shared->TexObjects, name, obj);
110
      }
111
   }
112
   return obj;
113
}
114
 
115
 
116
/*
117
 * Deallocate a texture object struct and remove it from the given
118
 * shared GL state.
119
 * Input:  shared - the shared GL state to which the object belongs
120
 *         t - the texture object to delete
121
 */
122
void _mesa_free_texture_object( struct gl_shared_state *shared,
123
                                struct gl_texture_object *t )
124
{
125
   struct gl_texture_object *tprev, *tcurr;
126
 
127
   assert(t);
128
 
129
   /* unlink t from the linked list */
130
   if (shared) {
131
      _glthread_LOCK_MUTEX(shared->Mutex);
132
      tprev = NULL;
133
      tcurr = shared->TexObjectList;
134
      while (tcurr) {
135
         if (tcurr==t) {
136
            if (tprev) {
137
               tprev->Next = t->Next;
138
            }
139
            else {
140
               shared->TexObjectList = t->Next;
141
            }
142
            break;
143
         }
144
         tprev = tcurr;
145
         tcurr = tcurr->Next;
146
      }
147
      _glthread_UNLOCK_MUTEX(shared->Mutex);
148
   }
149
 
150
   if (t->Name) {
151
      /* remove from hash table */
152
      _mesa_HashRemove(shared->TexObjects, t->Name);
153
   }
154
 
155
   _mesa_free_colortable_data(&t->Palette);
156
 
157
   /* free the texture images */
158
   {
159
      GLuint i;
160
      for (i=0;i<MAX_TEXTURE_LEVELS;i++) {
161
         if (t->Image[i]) {
162
            _mesa_free_texture_image( t->Image[i] );
163
         }
164
      }
165
   }
166
 
167
   /* free this object */
168
   FREE( t );
169
}
170
 
171
 
172
/*
173
 * Copy texture object state from one texture object to another.
174
 */
175
void
176
_mesa_copy_texture_object( struct gl_texture_object *dest,
177
                           const struct gl_texture_object *src )
178
{
179
   dest->Name = src->Name;
180
   dest->Priority = src->Priority;
181
   dest->BorderColor[0] = src->BorderColor[0];
182
   dest->BorderColor[1] = src->BorderColor[1];
183
   dest->BorderColor[2] = src->BorderColor[2];
184
   dest->BorderColor[3] = src->BorderColor[3];
185
   dest->WrapS = src->WrapS;
186
   dest->WrapT = src->WrapT;
187
   dest->WrapR = src->WrapR;
188
   dest->MinFilter = src->MinFilter;
189
   dest->MagFilter = src->MagFilter;
190
   dest->MinLod = src->MinLod;
191
   dest->MaxLod = src->MaxLod;
192
   dest->BaseLevel = src->BaseLevel;
193
   dest->MaxLevel = src->MaxLevel;
194
   dest->MaxAnisotropy = src->MaxAnisotropy;
195
   dest->CompareFlag = src->CompareFlag;
196
   dest->CompareOperator = src->CompareOperator;
197
   dest->ShadowAmbient = src->ShadowAmbient;
198
   dest->CompareMode = src->CompareMode;
199
   dest->CompareFunc = src->CompareFunc;
200
   dest->DepthMode = src->DepthMode;
201
   dest->_MaxLevel = src->_MaxLevel;
202
   dest->_MaxLambda = src->_MaxLambda;
203
   dest->GenerateMipmap = src->GenerateMipmap;
204
   dest->Palette = src->Palette;
205
   dest->Complete = src->Complete;
206
}
207
 
208
 
209
/*
210
 * Report why a texture object is incomplete.  (for debug only)
211
 */
212
#if 0
213
static void
214
incomplete(const struct gl_texture_object *t, const char *why)
215
{
216
   _mesa_printf("Texture Obj %d incomplete because: %s\n", t->Name, why);
217
}
218
#else
219
#define incomplete(a, b)
220
#endif
221
 
222
 
223
/*
224
 * Examine a texture object to determine if it is complete.
225
 * The t->Complete flag will be set to GL_TRUE or GL_FALSE accordingly.
226
 */
227
void
228
_mesa_test_texobj_completeness( const GLcontext *ctx,
229
                                struct gl_texture_object *t )
230
{
231
   const GLint baseLevel = t->BaseLevel;
232
   GLint maxLog2 = 0, maxLevels = 0;
233
 
234
   t->Complete = GL_TRUE;  /* be optimistic */
235
 
236
   /* Always need the base level image */
237
   if (!t->Image[baseLevel]) {
238
      incomplete(t, "Image[baseLevel] == NULL");
239
      t->Complete = GL_FALSE;
240
      return;
241
   }
242
 
243
   /* Compute _MaxLevel */
244
   if (t->Target == GL_TEXTURE_1D) {
245
      maxLog2 = t->Image[baseLevel]->WidthLog2;
246
      maxLevels = ctx->Const.MaxTextureLevels;
247
   }
248
   else if (t->Target == GL_TEXTURE_2D) {
249
      maxLog2 = MAX2(t->Image[baseLevel]->WidthLog2,
250
                     t->Image[baseLevel]->HeightLog2);
251
      maxLevels = ctx->Const.MaxTextureLevels;
252
   }
253
   else if (t->Target == GL_TEXTURE_3D) {
254
      GLint max = MAX2(t->Image[baseLevel]->WidthLog2,
255
                       t->Image[baseLevel]->HeightLog2);
256
      maxLog2 = MAX2(max, (GLint)(t->Image[baseLevel]->DepthLog2));
257
      maxLevels = ctx->Const.Max3DTextureLevels;
258
   }
259
   else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
260
      maxLog2 = MAX2(t->Image[baseLevel]->WidthLog2,
261
                     t->Image[baseLevel]->HeightLog2);
262
      maxLevels = ctx->Const.MaxCubeTextureLevels;
263
   }
264
   else if (t->Target == GL_TEXTURE_RECTANGLE_NV) {
265
      maxLog2 = 0;  /* not applicable */
266
      maxLevels = 1;  /* no mipmapping */
267
   }
268
   else {
269
      _mesa_problem(ctx, "Bad t->Target in _mesa_test_texobj_completeness");
270
      return;
271
   }
272
 
273
   ASSERT(maxLevels > 0);
274
 
275
   t->_MaxLevel = baseLevel + maxLog2;
276
   t->_MaxLevel = MIN2(t->_MaxLevel, t->MaxLevel);
277
   t->_MaxLevel = MIN2(t->_MaxLevel, maxLevels - 1);
278
 
279
   /* Compute _MaxLambda = q - b (see the 1.2 spec) used during mipmapping */
280
   t->_MaxLambda = (GLfloat) (t->_MaxLevel - t->BaseLevel);
281
 
282
   if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
283
      /* make sure that all six cube map level 0 images are the same size */
284
      const GLuint w = t->Image[baseLevel]->Width2;
285
      const GLuint h = t->Image[baseLevel]->Height2;
286
      if (!t->NegX[baseLevel] ||
287
          t->NegX[baseLevel]->Width2 != w ||
288
          t->NegX[baseLevel]->Height2 != h ||
289
          !t->PosY[baseLevel] ||
290
          t->PosY[baseLevel]->Width2 != w ||
291
          t->PosY[baseLevel]->Height2 != h ||
292
          !t->NegY[baseLevel] ||
293
          t->NegY[baseLevel]->Width2 != w ||
294
          t->NegY[baseLevel]->Height2 != h ||
295
          !t->PosZ[baseLevel] ||
296
          t->PosZ[baseLevel]->Width2 != w ||
297
          t->PosZ[baseLevel]->Height2 != h ||
298
          !t->NegZ[baseLevel] ||
299
          t->NegZ[baseLevel]->Width2 != w ||
300
          t->NegZ[baseLevel]->Height2 != h) {
301
         t->Complete = GL_FALSE;
302
         incomplete(t, "Non-quare cubemap image");
303
         return;
304
      }
305
   }
306
 
307
   if (t->MinFilter != GL_NEAREST && t->MinFilter != GL_LINEAR) {
308
      /*
309
       * Mipmapping: determine if we have a complete set of mipmaps
310
       */
311
      GLint i;
312
      GLint minLevel = baseLevel;
313
      GLint maxLevel = t->_MaxLevel;
314
 
315
      if (minLevel > maxLevel) {
316
         t->Complete = GL_FALSE;
317
         incomplete(t, "minLevel > maxLevel");
318
         return;
319
      }
320
 
321
      /* Test dimension-independent attributes */
322
      for (i = minLevel; i <= maxLevel; i++) {
323
         if (t->Image[i]) {
324
            if (t->Image[i]->TexFormat != t->Image[baseLevel]->TexFormat) {
325
               t->Complete = GL_FALSE;
326
               incomplete(t, "Format[i] != Format[baseLevel]");
327
               return;
328
            }
329
            if (t->Image[i]->Border != t->Image[baseLevel]->Border) {
330
               t->Complete = GL_FALSE;
331
               incomplete(t, "Border[i] != Border[baseLevel]");
332
               return;
333
            }
334
         }
335
      }
336
 
337
      /* Test things which depend on number of texture image dimensions */
338
      if (t->Target == GL_TEXTURE_1D) {
339
         /* Test 1-D mipmaps */
340
         GLuint width = t->Image[baseLevel]->Width2;
341
         for (i = baseLevel + 1; i < maxLevels; i++) {
342
            if (width > 1) {
343
               width /= 2;
344
            }
345
            if (i >= minLevel && i <= maxLevel) {
346
               if (!t->Image[i]) {
347
                  t->Complete = GL_FALSE;
348
                  incomplete(t, "1D Image[i] == NULL");
349
                  return;
350
               }
351
               if (t->Image[i]->Width2 != width ) {
352
                  t->Complete = GL_FALSE;
353
                  incomplete(t, "1D Image[i] bad width");
354
                  return;
355
               }
356
            }
357
            if (width == 1) {
358
               return;  /* found smallest needed mipmap, all done! */
359
            }
360
         }
361
      }
362
      else if (t->Target == GL_TEXTURE_2D) {
363
         /* Test 2-D mipmaps */
364
         GLuint width = t->Image[baseLevel]->Width2;
365
         GLuint height = t->Image[baseLevel]->Height2;
366
         for (i = baseLevel + 1; i < maxLevels; i++) {
367
            if (width > 1) {
368
               width /= 2;
369
            }
370
            if (height > 1) {
371
               height /= 2;
372
            }
373
            if (i >= minLevel && i <= maxLevel) {
374
               if (!t->Image[i]) {
375
                  t->Complete = GL_FALSE;
376
                  incomplete(t, "2D Image[i] == NULL");
377
                  return;
378
               }
379
               if (t->Image[i]->Width2 != width) {
380
                  t->Complete = GL_FALSE;
381
                  incomplete(t, "2D Image[i] bad width");
382
                  return;
383
               }
384
               if (t->Image[i]->Height2 != height) {
385
                  t->Complete = GL_FALSE;
386
                  incomplete(t, "2D Image[i] bad height");
387
                  return;
388
               }
389
               if (width==1 && height==1) {
390
                  return;  /* found smallest needed mipmap, all done! */
391
               }
392
            }
393
         }
394
      }
395
      else if (t->Target == GL_TEXTURE_3D) {
396
         /* Test 3-D mipmaps */
397
         GLuint width = t->Image[baseLevel]->Width2;
398
         GLuint height = t->Image[baseLevel]->Height2;
399
         GLuint depth = t->Image[baseLevel]->Depth2;
400
         for (i = baseLevel + 1; i < maxLevels; i++) {
401
            if (width > 1) {
402
               width /= 2;
403
            }
404
            if (height > 1) {
405
               height /= 2;
406
            }
407
            if (depth > 1) {
408
               depth /= 2;
409
            }
410
            if (i >= minLevel && i <= maxLevel) {
411
               if (!t->Image[i]) {
412
                  incomplete(t, "3D Image[i] == NULL");
413
                  t->Complete = GL_FALSE;
414
                  return;
415
               }
416
               if (t->Image[i]->Format == GL_DEPTH_COMPONENT) {
417
                  t->Complete = GL_FALSE;
418
                  incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex");
419
                  return;
420
               }
421
               if (t->Image[i]->Width2 != width) {
422
                  t->Complete = GL_FALSE;
423
                  incomplete(t, "3D Image[i] bad width");
424
                  return;
425
               }
426
               if (t->Image[i]->Height2 != height) {
427
                  t->Complete = GL_FALSE;
428
                  incomplete(t, "3D Image[i] bad height");
429
                  return;
430
               }
431
               if (t->Image[i]->Depth2 != depth) {
432
                  t->Complete = GL_FALSE;
433
                  incomplete(t, "3D Image[i] bad depth");
434
                  return;
435
               }
436
            }
437
            if (width == 1 && height == 1 && depth == 1) {
438
               return;  /* found smallest needed mipmap, all done! */
439
            }
440
         }
441
      }
442
      else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
443
         /* make sure 6 cube faces are consistant */
444
         GLuint width = t->Image[baseLevel]->Width2;
445
         GLuint height = t->Image[baseLevel]->Height2;
446
         for (i = baseLevel + 1; i < maxLevels; i++) {
447
            if (width > 1) {
448
               width /= 2;
449
            }
450
            if (height > 1) {
451
               height /= 2;
452
            }
453
            if (i >= minLevel && i <= maxLevel) {
454
               /* Don't support GL_DEPTH_COMPONENT for cube maps */
455
               if (t->Image[i]->Format == GL_DEPTH_COMPONENT) {
456
                  t->Complete = GL_FALSE;
457
                  incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex");
458
                  return;
459
               }
460
               /* check that we have images defined */
461
               if (!t->Image[i] || !t->NegX[i] ||
462
                   !t->PosY[i]  || !t->NegY[i] ||
463
                   !t->PosZ[i]  || !t->NegZ[i]) {
464
                  t->Complete = GL_FALSE;
465
                  incomplete(t, "CubeMap Image[i] == NULL");
466
                  return;
467
               }
468
               /* check that all six images have same size */
469
               if (t->NegX[i]->Width2!=width || t->NegX[i]->Height2!=height ||
470
                   t->PosY[i]->Width2!=width || t->PosY[i]->Height2!=height ||
471
                   t->NegY[i]->Width2!=width || t->NegY[i]->Height2!=height ||
472
                   t->PosZ[i]->Width2!=width || t->PosZ[i]->Height2!=height ||
473
                   t->NegZ[i]->Width2!=width || t->NegZ[i]->Height2!=height) {
474
                  t->Complete = GL_FALSE;
475
                  incomplete(t, "CubeMap Image[i] bad size");
476
                  return;
477
               }
478
            }
479
            if (width == 1 && height == 1) {
480
               return;  /* found smallest needed mipmap, all done! */
481
            }
482
         }
483
      }
484
      else if (t->Target == GL_TEXTURE_RECTANGLE_NV) {
485
         /* XXX special checking? */
486
 
487
      }
488
      else {
489
         /* Target = ??? */
490
         _mesa_problem(ctx, "Bug in gl_test_texture_object_completeness\n");
491
      }
492
   }
493
}
494
 
495
 
496
_glthread_DECLARE_STATIC_MUTEX(GenTexturesLock);
497
 
498
 
499
/*
500
 * Execute glGenTextures
501
 */
502
void
503
_mesa_GenTextures( GLsizei n, GLuint *texName )
504
{
505
   GET_CURRENT_CONTEXT(ctx);
506
   GLuint first;
507
   GLint i;
508
   ASSERT_OUTSIDE_BEGIN_END(ctx);
509
 
510
   if (n < 0) {
511
      _mesa_error( ctx, GL_INVALID_VALUE, "glGenTextures" );
512
      return;
513
   }
514
 
515
   if (!texName)
516
      return;
517
 
518
   /*
519
    * This must be atomic (generation and allocation of texture IDs)
520
    */
521
   _glthread_LOCK_MUTEX(GenTexturesLock);
522
 
523
   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->TexObjects, n);
524
 
525
   /* Return the texture names */
526
   for (i=0;i<n;i++) {
527
      texName[i] = first + i;
528
   }
529
 
530
   /* Allocate new, empty texture objects */
531
   for (i=0;i<n;i++) {
532
      GLuint name = first + i;
533
      GLenum target = 0;
534
      (void) _mesa_alloc_texture_object( ctx->Shared, name, target);
535
   }
536
 
537
   _glthread_UNLOCK_MUTEX(GenTexturesLock);
538
}
539
 
540
 
541
 
542
/*
543
 * Execute glDeleteTextures
544
 */
545
void
546
_mesa_DeleteTextures( GLsizei n, const GLuint *texName)
547
{
548
   GET_CURRENT_CONTEXT(ctx);
549
   GLint i;
550
   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */
551
 
552
   if (!texName)
553
      return;
554
 
555
   for (i=0;i<n;i++) {
556
      if (texName[i] > 0) {
557
         struct gl_texture_object *delObj = (struct gl_texture_object *)
558
            _mesa_HashLookup(ctx->Shared->TexObjects, texName[i]);
559
         if (delObj) {
560
            /* First check if this texture is currently bound.
561
             * If so, unbind it and decrement the reference count.
562
             */
563
            GLuint u;
564
            for (u = 0; u < MAX_TEXTURE_UNITS; u++) {
565
               struct gl_texture_unit *unit = &ctx->Texture.Unit[u];
566
               if (delObj == unit->Current1D) {
567
                  unit->Current1D = ctx->Shared->Default1D;
568
                  ctx->Shared->Default1D->RefCount++;
569
                  delObj->RefCount--;
570
                  if (delObj == unit->_Current)
571
                     unit->_Current = unit->Current1D;
572
               }
573
               else if (delObj == unit->Current2D) {
574
                  unit->Current2D = ctx->Shared->Default2D;
575
                  ctx->Shared->Default2D->RefCount++;
576
                  delObj->RefCount--;
577
                  if (delObj == unit->_Current)
578
                     unit->_Current = unit->Current2D;
579
               }
580
               else if (delObj == unit->Current3D) {
581
                  unit->Current3D = ctx->Shared->Default3D;
582
                  ctx->Shared->Default3D->RefCount++;
583
                  delObj->RefCount--;
584
                  if (delObj == unit->_Current)
585
                     unit->_Current = unit->Current3D;
586
               }
587
               else if (delObj == unit->CurrentCubeMap) {
588
                  unit->CurrentCubeMap = ctx->Shared->DefaultCubeMap;
589
                  ctx->Shared->DefaultCubeMap->RefCount++;
590
                  delObj->RefCount--;
591
                  if (delObj == unit->_Current)
592
                     unit->_Current = unit->CurrentCubeMap;
593
               }
594
               else if (delObj == unit->CurrentRect) {
595
                  unit->CurrentRect = ctx->Shared->DefaultRect;
596
                  ctx->Shared->DefaultRect->RefCount++;
597
                  delObj->RefCount--;
598
                  if (delObj == unit->_Current)
599
                     unit->_Current = unit->CurrentRect;
600
               }
601
            }
602
            ctx->NewState |= _NEW_TEXTURE;
603
 
604
            /* Decrement reference count and delete if zero */
605
            delObj->RefCount--;
606
            ASSERT(delObj->RefCount >= 0);
607
 
608
            if (delObj->RefCount == 0) {
609
               ASSERT(delObj->Name != 0);
610
               if (ctx->Driver.DeleteTexture)
611
                  (*ctx->Driver.DeleteTexture)( ctx, delObj );
612
               _mesa_free_texture_object(ctx->Shared, delObj);
613
            }
614
         }
615
      }
616
   }
617
}
618
 
619
 
620
 
621
/*
622
 * Execute glBindTexture
623
 */
624
void
625
_mesa_BindTexture( GLenum target, GLuint texName )
626
{
627
   GET_CURRENT_CONTEXT(ctx);
628
   GLuint unit = ctx->Texture.CurrentUnit;
629
   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
630
   struct gl_texture_object *oldTexObj;
631
   struct gl_texture_object *newTexObj = 0;
632
   ASSERT_OUTSIDE_BEGIN_END(ctx);
633
 
634
   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
635
      _mesa_debug(ctx, "glBindTexture %s %d\n",
636
                  _mesa_lookup_enum_by_nr(target), (GLint) texName);
637
 
638
   switch (target) {
639
      case GL_TEXTURE_1D:
640
         oldTexObj = texUnit->Current1D;
641
         break;
642
      case GL_TEXTURE_2D:
643
         oldTexObj = texUnit->Current2D;
644
         break;
645
      case GL_TEXTURE_3D:
646
         oldTexObj = texUnit->Current3D;
647
         break;
648
      case GL_TEXTURE_CUBE_MAP_ARB:
649
         if (!ctx->Extensions.ARB_texture_cube_map) {
650
            _mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" );
651
            return;
652
         }
653
         oldTexObj = texUnit->CurrentCubeMap;
654
         break;
655
      case GL_TEXTURE_RECTANGLE_NV:
656
         if (!ctx->Extensions.NV_texture_rectangle) {
657
            _mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" );
658
            return;
659
         }
660
         oldTexObj = texUnit->CurrentRect;
661
         break;
662
      default:
663
         _mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" );
664
         return;
665
   }
666
 
667
   if (oldTexObj->Name == texName)
668
      return;   /* rebinding the same texture- no change */
669
 
670
   /*
671
    * Get pointer to new texture object (newTexObj)
672
    */
673
   if (texName == 0) {
674
      /* newTexObj = a default texture object */
675
      switch (target) {
676
         case GL_TEXTURE_1D:
677
            newTexObj = ctx->Shared->Default1D;
678
            break;
679
         case GL_TEXTURE_2D:
680
            newTexObj = ctx->Shared->Default2D;
681
            break;
682
         case GL_TEXTURE_3D:
683
            newTexObj = ctx->Shared->Default3D;
684
            break;
685
         case GL_TEXTURE_CUBE_MAP_ARB:
686
            newTexObj = ctx->Shared->DefaultCubeMap;
687
            break;
688
         case GL_TEXTURE_RECTANGLE_NV:
689
            newTexObj = ctx->Shared->DefaultRect;
690
            break;
691
         default:
692
            ; /* Bad targets are caught above */
693
      }
694
   }
695
   else {
696
      /* non-default texture object */
697
      const struct _mesa_HashTable *hash = ctx->Shared->TexObjects;
698
      newTexObj = (struct gl_texture_object *) _mesa_HashLookup(hash, texName);
699
      if (newTexObj) {
700
         /* error checking */
701
         if (newTexObj->Target != 0 && newTexObj->Target != target) {
702
            /* the named texture object's dimensions don't match the target */
703
            _mesa_error( ctx, GL_INVALID_OPERATION,
704
                         "glBindTexture(wrong dimensionality)" );
705
            return;
706
         }
707
         if (newTexObj->Target == 0 && target == GL_TEXTURE_RECTANGLE_NV) {
708
            /* have to init wrap and filter state here - kind of klunky */
709
            newTexObj->WrapS = GL_CLAMP_TO_EDGE;
710
            newTexObj->WrapT = GL_CLAMP_TO_EDGE;
711
            newTexObj->WrapR = GL_CLAMP_TO_EDGE;
712
            newTexObj->MinFilter = GL_LINEAR;
713
         }
714
      }
715
      else {
716
         /* if this is a new texture id, allocate a texture object now */
717
         newTexObj = _mesa_alloc_texture_object( ctx->Shared, texName,
718
                                                 target);
719
         if (!newTexObj) {
720
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture");
721
            return;
722
         }
723
      }
724
      newTexObj->Target = target;
725
   }
726
 
727
   newTexObj->RefCount++;
728
 
729
   /* do the actual binding, but first flush outstanding vertices:
730
    */
731
   FLUSH_VERTICES(ctx, _NEW_TEXTURE);
732
 
733
   switch (target) {
734
      case GL_TEXTURE_1D:
735
         texUnit->Current1D = newTexObj;
736
         break;
737
      case GL_TEXTURE_2D:
738
         texUnit->Current2D = newTexObj;
739
         break;
740
      case GL_TEXTURE_3D:
741
         texUnit->Current3D = newTexObj;
742
         break;
743
      case GL_TEXTURE_CUBE_MAP_ARB:
744
         texUnit->CurrentCubeMap = newTexObj;
745
         break;
746
      case GL_TEXTURE_RECTANGLE_NV:
747
         texUnit->CurrentRect = newTexObj;
748
         break;
749
      default:
750
         _mesa_problem(ctx, "bad target in BindTexture");
751
         return;
752
   }
753
 
754
   /* Pass BindTexture call to device driver */
755
   if (ctx->Driver.BindTexture)
756
      (*ctx->Driver.BindTexture)( ctx, target, newTexObj );
757
 
758
   oldTexObj->RefCount--;
759
   assert(oldTexObj->RefCount >= 0);
760
   if (oldTexObj->RefCount == 0) {
761
      assert(oldTexObj->Name != 0);
762
      if (ctx->Driver.DeleteTexture) {
763
         (*ctx->Driver.DeleteTexture)( ctx, oldTexObj );
764
      }
765
      _mesa_free_texture_object(ctx->Shared, oldTexObj);
766
   }
767
}
768
 
769
 
770
 
771
/*
772
 * Execute glPrioritizeTextures
773
 */
774
void
775
_mesa_PrioritizeTextures( GLsizei n, const GLuint *texName,
776
                          const GLclampf *priorities )
777
{
778
   GET_CURRENT_CONTEXT(ctx);
779
   GLint i;
780
   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
781
 
782
   if (n < 0) {
783
      _mesa_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" );
784
      return;
785
   }
786
 
787
   if (!priorities)
788
      return;
789
 
790
   for (i = 0; i < n; i++) {
791
      if (texName[i] > 0) {
792
         struct gl_texture_object *t = (struct gl_texture_object *)
793
            _mesa_HashLookup(ctx->Shared->TexObjects, texName[i]);
794
         if (t) {
795
            t->Priority = CLAMP( priorities[i], 0.0F, 1.0F );
796
            if (ctx->Driver.PrioritizeTexture)
797
               ctx->Driver.PrioritizeTexture( ctx, t, t->Priority );
798
         }
799
      }
800
   }
801
 
802
   ctx->NewState |= _NEW_TEXTURE;
803
}
804
 
805
 
806
 
807
/*
808
 * Execute glAreTexturesResident
809
 */
810
GLboolean
811
_mesa_AreTexturesResident(GLsizei n, const GLuint *texName,
812
                          GLboolean *residences)
813
{
814
   GET_CURRENT_CONTEXT(ctx);
815
   GLboolean allResident = GL_TRUE;
816
   GLint i;
817
   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
818
 
819
   if (n < 0) {
820
      _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)");
821
      return GL_FALSE;
822
   }
823
 
824
   if (!texName || !residences)
825
      return GL_FALSE;
826
 
827
   for (i = 0; i < n; i++) {
828
      struct gl_texture_object *t;
829
      if (texName[i] == 0) {
830
         _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(textures)");
831
         return GL_FALSE;
832
      }
833
      t = (struct gl_texture_object *)
834
         _mesa_HashLookup(ctx->Shared->TexObjects, texName[i]);
835
      if (t) {
836
         if (ctx->Driver.IsTextureResident) {
837
            residences[i] = ctx->Driver.IsTextureResident(ctx, t);
838
            if (!residences[i])
839
               allResident = GL_FALSE;
840
         }
841
         else {
842
            residences[i] = GL_TRUE;
843
         }
844
      }
845
      else {
846
         _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(textures)");
847
         return GL_FALSE;
848
      }
849
   }
850
   return allResident;
851
}
852
 
853
 
854
 
855
/*
856
 * Execute glIsTexture
857
 */
858
GLboolean
859
_mesa_IsTexture( GLuint texture )
860
{
861
   GET_CURRENT_CONTEXT(ctx);
862
   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
863
   return texture > 0 && _mesa_HashLookup(ctx->Shared->TexObjects, texture);
864
}