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