5cf71e872d87d7851460338c6ce645b5fe188628
[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 textures 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 textures.
589 * Corresponding empty texture objects are also generated.
590 */
591 void GLAPIENTRY
592 _mesa_GenTextures( GLsizei n, GLuint *textures )
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 (!textures)
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 textures[i] = name;
626 }
627
628 _glthread_UNLOCK_MUTEX(GenTexturesLock);
629 }
630
631
632 /**
633 * Delete named textures.
634 *
635 * \param n number of textures to be deleted.
636 * \param textures array of texture IDs to be deleted.
637 *
638 * \sa glDeleteTextures().
639 *
640 * If we're about to delete a texture that's currently bound to any
641 * texture unit, unbind the texture first. Decrement the reference
642 * count on the texture object and delete it if it's zero.
643 * Recall that texture objects can be shared among several rendering
644 * contexts.
645 */
646 void GLAPIENTRY
647 _mesa_DeleteTextures( GLsizei n, const GLuint *textures)
648 {
649 GET_CURRENT_CONTEXT(ctx);
650 GLint i;
651 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */
652
653 if (!textures)
654 return;
655
656 for (i = 0; i < n; i++) {
657 if (textures[i] > 0) {
658 struct gl_texture_object *delObj = (struct gl_texture_object *)
659 _mesa_HashLookup(ctx->Shared->TexObjects, textures[i]);
660 if (delObj) {
661 /* First check if this texture is currently bound.
662 * If so, unbind it and decrement the reference count.
663 */
664 GLuint u;
665 for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) {
666 struct gl_texture_unit *unit = &ctx->Texture.Unit[u];
667 if (delObj == unit->Current1D) {
668 unit->Current1D = ctx->Shared->Default1D;
669 ctx->Shared->Default1D->RefCount++;
670 delObj->RefCount--;
671 if (delObj == unit->_Current)
672 unit->_Current = unit->Current1D;
673 }
674 else if (delObj == unit->Current2D) {
675 unit->Current2D = ctx->Shared->Default2D;
676 ctx->Shared->Default2D->RefCount++;
677 delObj->RefCount--;
678 if (delObj == unit->_Current)
679 unit->_Current = unit->Current2D;
680 }
681 else if (delObj == unit->Current3D) {
682 unit->Current3D = ctx->Shared->Default3D;
683 ctx->Shared->Default3D->RefCount++;
684 delObj->RefCount--;
685 if (delObj == unit->_Current)
686 unit->_Current = unit->Current3D;
687 }
688 else if (delObj == unit->CurrentCubeMap) {
689 unit->CurrentCubeMap = ctx->Shared->DefaultCubeMap;
690 ctx->Shared->DefaultCubeMap->RefCount++;
691 delObj->RefCount--;
692 if (delObj == unit->_Current)
693 unit->_Current = unit->CurrentCubeMap;
694 }
695 else if (delObj == unit->CurrentRect) {
696 unit->CurrentRect = ctx->Shared->DefaultRect;
697 ctx->Shared->DefaultRect->RefCount++;
698 delObj->RefCount--;
699 if (delObj == unit->_Current)
700 unit->_Current = unit->CurrentRect;
701 }
702 }
703 ctx->NewState |= _NEW_TEXTURE;
704
705 /* Decrement reference count and delete if zero */
706 delObj->RefCount--;
707 ASSERT(delObj->RefCount >= 0);
708
709 if (delObj->RefCount == 0) {
710 ASSERT(delObj->Name != 0);
711 _mesa_remove_texture_object(ctx, delObj);
712 ASSERT(ctx->Driver.DeleteTexture);
713 (*ctx->Driver.DeleteTexture)(ctx, delObj);
714 }
715 }
716 }
717 }
718 }
719
720 /**
721 * Bind a named texture to a texturing target.
722 *
723 * \param target texture target.
724 * \param texName texture name.
725 *
726 * \sa glBindTexture().
727 *
728 * Determines the old texture object bound and returns immediately if rebinding
729 * the same texture. Get the current texture which is either a default texture
730 * if name is null, a named texture from the hash, or a new texture if the
731 * given texture name is new. Increments its reference count, binds it, and
732 * calls dd_function_table::BindTexture. Decrements the old texture reference
733 * count and deletes it if it reaches zero.
734 */
735 void GLAPIENTRY
736 _mesa_BindTexture( GLenum target, GLuint texName )
737 {
738 GET_CURRENT_CONTEXT(ctx);
739 GLuint unit = ctx->Texture.CurrentUnit;
740 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
741 struct gl_texture_object *oldTexObj;
742 struct gl_texture_object *newTexObj = 0;
743 ASSERT_OUTSIDE_BEGIN_END(ctx);
744
745 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
746 _mesa_debug(ctx, "glBindTexture %s %d\n",
747 _mesa_lookup_enum_by_nr(target), (GLint) texName);
748
749 switch (target) {
750 case GL_TEXTURE_1D:
751 oldTexObj = texUnit->Current1D;
752 break;
753 case GL_TEXTURE_2D:
754 oldTexObj = texUnit->Current2D;
755 break;
756 case GL_TEXTURE_3D:
757 oldTexObj = texUnit->Current3D;
758 break;
759 case GL_TEXTURE_CUBE_MAP_ARB:
760 if (!ctx->Extensions.ARB_texture_cube_map) {
761 _mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" );
762 return;
763 }
764 oldTexObj = texUnit->CurrentCubeMap;
765 break;
766 case GL_TEXTURE_RECTANGLE_NV:
767 if (!ctx->Extensions.NV_texture_rectangle) {
768 _mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" );
769 return;
770 }
771 oldTexObj = texUnit->CurrentRect;
772 break;
773 default:
774 _mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" );
775 return;
776 }
777
778 if (oldTexObj->Name == texName)
779 return; /* rebinding the same texture- no change */
780
781 /*
782 * Get pointer to new texture object (newTexObj)
783 */
784 if (texName == 0) {
785 /* newTexObj = a default texture object */
786 switch (target) {
787 case GL_TEXTURE_1D:
788 newTexObj = ctx->Shared->Default1D;
789 break;
790 case GL_TEXTURE_2D:
791 newTexObj = ctx->Shared->Default2D;
792 break;
793 case GL_TEXTURE_3D:
794 newTexObj = ctx->Shared->Default3D;
795 break;
796 case GL_TEXTURE_CUBE_MAP_ARB:
797 newTexObj = ctx->Shared->DefaultCubeMap;
798 break;
799 case GL_TEXTURE_RECTANGLE_NV:
800 newTexObj = ctx->Shared->DefaultRect;
801 break;
802 default:
803 ; /* Bad targets are caught above */
804 }
805 }
806 else {
807 /* non-default texture object */
808 const struct _mesa_HashTable *hash = ctx->Shared->TexObjects;
809 newTexObj = (struct gl_texture_object *) _mesa_HashLookup(hash, texName);
810 if (newTexObj) {
811 /* error checking */
812 if (newTexObj->Target != 0 && newTexObj->Target != target) {
813 /* the named texture object's dimensions don't match the target */
814 _mesa_error( ctx, GL_INVALID_OPERATION,
815 "glBindTexture(wrong dimensionality)" );
816 return;
817 }
818 if (newTexObj->Target == 0 && target == GL_TEXTURE_RECTANGLE_NV) {
819 /* have to init wrap and filter state here - kind of klunky */
820 newTexObj->WrapS = GL_CLAMP_TO_EDGE;
821 newTexObj->WrapT = GL_CLAMP_TO_EDGE;
822 newTexObj->WrapR = GL_CLAMP_TO_EDGE;
823 newTexObj->MinFilter = GL_LINEAR;
824 if (ctx->Driver.TexParameter) {
825 static const GLfloat fparam_wrap[1] = {(GLfloat) GL_CLAMP_TO_EDGE};
826 static const GLfloat fparam_filter[1] = {(GLfloat) GL_LINEAR};
827 (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_WRAP_S, fparam_wrap );
828 (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_WRAP_T, fparam_wrap );
829 (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_WRAP_R, fparam_wrap );
830 (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_MIN_FILTER, fparam_filter );
831 }
832 }
833 }
834 else {
835 /* if this is a new texture id, allocate a texture object now */
836 newTexObj = (*ctx->Driver.NewTextureObject)(ctx, texName, target);
837 if (!newTexObj) {
838 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture");
839 return;
840 }
841 _mesa_save_texture_object(ctx, newTexObj);
842 }
843 newTexObj->Target = target;
844 }
845
846 newTexObj->RefCount++;
847
848 /* do the actual binding, but first flush outstanding vertices:
849 */
850 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
851
852 switch (target) {
853 case GL_TEXTURE_1D:
854 texUnit->Current1D = newTexObj;
855 break;
856 case GL_TEXTURE_2D:
857 texUnit->Current2D = newTexObj;
858 break;
859 case GL_TEXTURE_3D:
860 texUnit->Current3D = newTexObj;
861 break;
862 case GL_TEXTURE_CUBE_MAP_ARB:
863 texUnit->CurrentCubeMap = newTexObj;
864 break;
865 case GL_TEXTURE_RECTANGLE_NV:
866 texUnit->CurrentRect = newTexObj;
867 break;
868 default:
869 _mesa_problem(ctx, "bad target in BindTexture");
870 return;
871 }
872
873 /* Pass BindTexture call to device driver */
874 if (ctx->Driver.BindTexture)
875 (*ctx->Driver.BindTexture)( ctx, target, newTexObj );
876
877 oldTexObj->RefCount--;
878 assert(oldTexObj->RefCount >= 0);
879 if (oldTexObj->RefCount == 0) {
880 assert(oldTexObj->Name != 0);
881 _mesa_remove_texture_object(ctx, oldTexObj);
882 ASSERT(ctx->Driver.DeleteTexture);
883 (*ctx->Driver.DeleteTexture)( ctx, oldTexObj );
884 }
885 }
886
887 /**
888 * Set texture priorities.
889 *
890 * \param n number of textures.
891 * \param texName texture names.
892 * \param priorities corresponding texture priorities.
893 *
894 * \sa glPrioritizeTextures().
895 *
896 * Looks up each texture in the hash, clamps the corresponding priority between
897 * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture.
898 */
899 void GLAPIENTRY
900 _mesa_PrioritizeTextures( GLsizei n, const GLuint *texName,
901 const GLclampf *priorities )
902 {
903 GET_CURRENT_CONTEXT(ctx);
904 GLint i;
905 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
906
907 if (n < 0) {
908 _mesa_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" );
909 return;
910 }
911
912 if (!priorities)
913 return;
914
915 for (i = 0; i < n; i++) {
916 if (texName[i] > 0) {
917 struct gl_texture_object *t = (struct gl_texture_object *)
918 _mesa_HashLookup(ctx->Shared->TexObjects, texName[i]);
919 if (t) {
920 t->Priority = CLAMP( priorities[i], 0.0F, 1.0F );
921 if (ctx->Driver.PrioritizeTexture)
922 ctx->Driver.PrioritizeTexture( ctx, t, t->Priority );
923 }
924 }
925 }
926
927 ctx->NewState |= _NEW_TEXTURE;
928 }
929
930 /**
931 * See if textures are loaded in texture memory.
932 *
933 * \param n number of textures to query.
934 * \param texName array with the texture names.
935 * \param residences array which will hold the residence status.
936 *
937 * \return GL_TRUE if all textures are resident and \p residences is left unchanged,
938 *
939 * \sa glAreTexturesResident().
940 *
941 * Looks up each texture in the hash and calls
942 * dd_function_table::IsTextureResident.
943 */
944 GLboolean GLAPIENTRY
945 _mesa_AreTexturesResident(GLsizei n, const GLuint *texName,
946 GLboolean *residences)
947 {
948 GET_CURRENT_CONTEXT(ctx);
949 GLboolean allResident = GL_TRUE;
950 GLint i, j;
951 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
952
953 if (n < 0) {
954 _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)");
955 return GL_FALSE;
956 }
957
958 if (!texName || !residences)
959 return GL_FALSE;
960
961 for (i = 0; i < n; i++) {
962 struct gl_texture_object *t;
963 if (texName[i] == 0) {
964 _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident");
965 return GL_FALSE;
966 }
967 t = (struct gl_texture_object *)
968 _mesa_HashLookup(ctx->Shared->TexObjects, texName[i]);
969 if (!t) {
970 _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident");
971 return GL_FALSE;
972 }
973 if (!ctx->Driver.IsTextureResident ||
974 ctx->Driver.IsTextureResident(ctx, t)) {
975 /* The texture is resident */
976 if (!allResident)
977 residences[i] = GL_TRUE;
978 }
979 else {
980 /* The texture is not resident */
981 if (allResident) {
982 allResident = GL_FALSE;
983 for (j = 0; j < i; j++)
984 residences[j] = GL_TRUE;
985 }
986 residences[i] = GL_FALSE;
987 }
988 }
989
990 return allResident;
991 }
992
993 /**
994 * See if a name corresponds to a texture.
995 *
996 * \param texture texture name.
997 *
998 * \return GL_TRUE if texture name corresponds to a texture, or GL_FALSE
999 * otherwise.
1000 *
1001 * \sa glIsTexture().
1002 *
1003 * Calls _mesa_HashLookup().
1004 */
1005 GLboolean GLAPIENTRY
1006 _mesa_IsTexture( GLuint texture )
1007 {
1008 GET_CURRENT_CONTEXT(ctx);
1009 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1010 return texture > 0 && _mesa_HashLookup(ctx->Shared->TexObjects, texture);
1011 }
1012
1013 /*@}*/