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