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