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