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