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