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