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