In gl_texture_image replace IntFormat with InternalFormat and Format with
[mesa.git] / src / mesa / main / texobj.c
1 /**
2 * \file texobj.c
3 * Texture object management.
4 */
5
6 /*
7 * Mesa 3-D graphics library
8 * Version: 6.3
9 *
10 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
26 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 */
29
30
31 #include "glheader.h"
32 #include "colortab.h"
33 #include "context.h"
34 #include "enums.h"
35 #include "hash.h"
36 #include "imports.h"
37 #include "macros.h"
38 #include "teximage.h"
39 #include "texstate.h"
40 #include "texobj.h"
41 #include "mtypes.h"
42
43 #ifdef __VMS
44 #define _mesa_sprintf sprintf
45 #endif
46
47 /**********************************************************************/
48 /** \name Internal functions */
49 /*@{*/
50
51 /**
52 * Allocate and initialize a new texture object. But don't put it into the
53 * texture object hash table.
54 *
55 * Called via ctx->Driver.NewTextureObject, unless overridden by a device
56 * driver.
57 *
58 * \param shared the shared GL state structure to contain the texture object
59 * \param name integer name for the texture object
60 * \param target either GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D,
61 * GL_TEXTURE_CUBE_MAP_ARB or GL_TEXTURE_RECTANGLE_NV. zero is ok for the sake
62 * of GenTextures()
63 *
64 * \return pointer to new texture object.
65 */
66 struct gl_texture_object *
67 _mesa_new_texture_object( GLcontext *ctx, GLuint name, GLenum target )
68 {
69 struct gl_texture_object *obj;
70 (void) ctx;
71 obj = MALLOC_STRUCT(gl_texture_object);
72 _mesa_initialize_texture_object(obj, name, target);
73 return obj;
74 }
75
76
77 /**
78 * Initialize a new texture object to default values.
79 * \param obj the texture object
80 * \param name the texture name
81 * \param target the texture target
82 */
83 void
84 _mesa_initialize_texture_object( struct gl_texture_object *obj,
85 GLuint name, GLenum target )
86 {
87 ASSERT(target == 0 ||
88 target == GL_TEXTURE_1D ||
89 target == GL_TEXTURE_2D ||
90 target == GL_TEXTURE_3D ||
91 target == GL_TEXTURE_CUBE_MAP_ARB ||
92 target == GL_TEXTURE_RECTANGLE_NV);
93
94 _mesa_bzero(obj, sizeof(*obj));
95 /* init the non-zero fields */
96 _glthread_INIT_MUTEX(obj->Mutex);
97 obj->RefCount = 1;
98 obj->Name = name;
99 obj->Target = target;
100 obj->Priority = 1.0F;
101 if (target == GL_TEXTURE_RECTANGLE_NV) {
102 obj->WrapS = GL_CLAMP_TO_EDGE;
103 obj->WrapT = GL_CLAMP_TO_EDGE;
104 obj->WrapR = GL_CLAMP_TO_EDGE;
105 obj->MinFilter = GL_LINEAR;
106 }
107 else {
108 obj->WrapS = GL_REPEAT;
109 obj->WrapT = GL_REPEAT;
110 obj->WrapR = GL_REPEAT;
111 obj->MinFilter = GL_NEAREST_MIPMAP_LINEAR;
112 }
113 obj->MagFilter = GL_LINEAR;
114 obj->MinLod = -1000.0;
115 obj->MaxLod = 1000.0;
116 obj->LodBias = 0.0;
117 obj->BaseLevel = 0;
118 obj->MaxLevel = 1000;
119 obj->MaxAnisotropy = 1.0;
120 obj->CompareFlag = GL_FALSE; /* SGIX_shadow */
121 obj->CompareOperator = GL_TEXTURE_LEQUAL_R_SGIX; /* SGIX_shadow */
122 obj->CompareMode = GL_NONE; /* ARB_shadow */
123 obj->CompareFunc = GL_LEQUAL; /* ARB_shadow */
124 obj->DepthMode = GL_LUMINANCE; /* ARB_depth_texture */
125 obj->ShadowAmbient = 0.0F; /* ARB/SGIX_shadow_ambient */
126 _mesa_init_colortable(&obj->Palette);
127 }
128
129
130 /**
131 * Deallocate a texture object struct. It should have already been
132 * removed from the texture object pool.
133 *
134 * \param shared the shared GL state to which the object belongs.
135 * \param texOjb the texture object to delete.
136 */
137 void
138 _mesa_delete_texture_object( GLcontext *ctx, struct gl_texture_object *texObj )
139 {
140 GLuint i, face;
141
142 (void) ctx;
143
144 _mesa_free_colortable_data(&texObj->Palette);
145
146 /* free the texture images */
147 for (face = 0; face < 6; face++) {
148 for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
149 if (texObj->Image[face][i]) {
150 _mesa_delete_texture_image( ctx, texObj->Image[face][i] );
151 }
152 }
153 }
154
155 /* destroy the mutex -- it may have allocated memory (eg on bsd) */
156 _glthread_DESTROY_MUTEX(texObj->Mutex);
157
158 /* free this object */
159 _mesa_free(texObj);
160 }
161
162
163
164
165 /**
166 * Copy texture object state from one texture object to another.
167 * Use for glPush/PopAttrib.
168 *
169 * \param dest destination texture object.
170 * \param src source texture object.
171 */
172 void
173 _mesa_copy_texture_object( struct gl_texture_object *dest,
174 const struct gl_texture_object *src )
175 {
176 dest->Name = src->Name;
177 dest->Priority = src->Priority;
178 dest->BorderColor[0] = src->BorderColor[0];
179 dest->BorderColor[1] = src->BorderColor[1];
180 dest->BorderColor[2] = src->BorderColor[2];
181 dest->BorderColor[3] = src->BorderColor[3];
182 dest->WrapS = src->WrapS;
183 dest->WrapT = src->WrapT;
184 dest->WrapR = src->WrapR;
185 dest->MinFilter = src->MinFilter;
186 dest->MagFilter = src->MagFilter;
187 dest->MinLod = src->MinLod;
188 dest->MaxLod = src->MaxLod;
189 dest->LodBias = src->LodBias;
190 dest->BaseLevel = src->BaseLevel;
191 dest->MaxLevel = src->MaxLevel;
192 dest->MaxAnisotropy = src->MaxAnisotropy;
193 dest->CompareFlag = src->CompareFlag;
194 dest->CompareOperator = src->CompareOperator;
195 dest->ShadowAmbient = src->ShadowAmbient;
196 dest->CompareMode = src->CompareMode;
197 dest->CompareFunc = src->CompareFunc;
198 dest->DepthMode = src->DepthMode;
199 dest->_MaxLevel = src->_MaxLevel;
200 dest->_MaxLambda = src->_MaxLambda;
201 dest->GenerateMipmap = src->GenerateMipmap;
202 dest->Palette = src->Palette;
203 dest->Complete = src->Complete;
204 dest->_IsPowerOfTwo = src->_IsPowerOfTwo;
205 }
206
207
208 /**
209 * Report why a texture object is incomplete.
210 *
211 * \param t texture object.
212 * \param why string describing why it's incomplete.
213 *
214 * \note For debug purposes only.
215 */
216 #if 0
217 static void
218 incomplete(const struct gl_texture_object *t, const char *why)
219 {
220 _mesa_printf("Texture Obj %d incomplete because: %s\n", t->Name, why);
221 }
222 #else
223 #define incomplete(t, why)
224 #endif
225
226
227 /**
228 * Examine a texture object to determine if it is complete.
229 *
230 * The gl_texture_object::Complete flag will be set to GL_TRUE or GL_FALSE
231 * accordingly.
232 *
233 * \param ctx GL context.
234 * \param t texture object.
235 *
236 * According to the texture target, verifies that each of the mipmaps is
237 * present and has the expected size.
238 */
239 void
240 _mesa_test_texobj_completeness( const GLcontext *ctx,
241 struct gl_texture_object *t )
242 {
243 const GLint baseLevel = t->BaseLevel;
244 GLint maxLog2 = 0, maxLevels = 0;
245
246 t->Complete = GL_TRUE; /* be optimistic */
247 t->_IsPowerOfTwo = GL_TRUE; /* may be set FALSE below */
248
249 /* Always need the base level image */
250 if (!t->Image[0][baseLevel]) {
251 char s[100];
252 _mesa_sprintf(s, "obj %p (%d) Image[baseLevel=%d] == NULL",
253 (void *) t, t->Name, baseLevel);
254 incomplete(t, s);
255 t->Complete = GL_FALSE;
256 return;
257 }
258
259 /* Check width/height/depth for zero */
260 if (t->Image[0][baseLevel]->Width == 0 ||
261 t->Image[0][baseLevel]->Height == 0 ||
262 t->Image[0][baseLevel]->Depth == 0) {
263 incomplete(t, "texture width = 0");
264 t->Complete = GL_FALSE;
265 return;
266 }
267
268 /* Compute _MaxLevel */
269 if (t->Target == GL_TEXTURE_1D) {
270 maxLog2 = t->Image[0][baseLevel]->WidthLog2;
271 maxLevels = ctx->Const.MaxTextureLevels;
272 }
273 else if (t->Target == GL_TEXTURE_2D) {
274 maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2,
275 t->Image[0][baseLevel]->HeightLog2);
276 maxLevels = ctx->Const.MaxTextureLevels;
277 }
278 else if (t->Target == GL_TEXTURE_3D) {
279 GLint max = MAX2(t->Image[0][baseLevel]->WidthLog2,
280 t->Image[0][baseLevel]->HeightLog2);
281 maxLog2 = MAX2(max, (GLint)(t->Image[0][baseLevel]->DepthLog2));
282 maxLevels = ctx->Const.Max3DTextureLevels;
283 }
284 else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
285 maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2,
286 t->Image[0][baseLevel]->HeightLog2);
287 maxLevels = ctx->Const.MaxCubeTextureLevels;
288 }
289 else if (t->Target == GL_TEXTURE_RECTANGLE_NV) {
290 maxLog2 = 0; /* not applicable */
291 maxLevels = 1; /* no mipmapping */
292 }
293 else {
294 _mesa_problem(ctx, "Bad t->Target in _mesa_test_texobj_completeness");
295 return;
296 }
297
298 ASSERT(maxLevels > 0);
299
300 t->_MaxLevel = baseLevel + maxLog2;
301 t->_MaxLevel = MIN2(t->_MaxLevel, t->MaxLevel);
302 t->_MaxLevel = MIN2(t->_MaxLevel, maxLevels - 1);
303
304 /* Compute _MaxLambda = q - b (see the 1.2 spec) used during mipmapping */
305 t->_MaxLambda = (GLfloat) (t->_MaxLevel - t->BaseLevel);
306
307 if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
308 /* make sure that all six cube map level 0 images are the same size */
309 const GLuint w = t->Image[0][baseLevel]->Width2;
310 const GLuint h = t->Image[0][baseLevel]->Height2;
311 GLuint face;
312 for (face = 1; face < 6; face++) {
313 if (t->Image[face][baseLevel] == NULL ||
314 t->Image[face][baseLevel]->Width2 != w ||
315 t->Image[face][baseLevel]->Height2 != h) {
316 t->Complete = GL_FALSE;
317 incomplete(t, "Non-quare cubemap image");
318 return;
319 }
320 }
321 }
322
323 /* check for non power of two */
324 if (!t->Image[0][baseLevel]->_IsPowerOfTwo) {
325 t->_IsPowerOfTwo = GL_FALSE;
326 }
327
328 /* extra checking for mipmaps */
329 if (t->MinFilter != GL_NEAREST && t->MinFilter != GL_LINEAR) {
330 /*
331 * Mipmapping: determine if we have a complete set of mipmaps
332 */
333 GLint i;
334 GLint minLevel = baseLevel;
335 GLint maxLevel = t->_MaxLevel;
336
337 if (minLevel > maxLevel) {
338 t->Complete = GL_FALSE;
339 incomplete(t, "minLevel > maxLevel");
340 return;
341 }
342
343 /* Test dimension-independent attributes */
344 for (i = minLevel; i <= maxLevel; i++) {
345 if (t->Image[0][i]) {
346 if (t->Image[0][i]->TexFormat != t->Image[0][baseLevel]->TexFormat) {
347 t->Complete = GL_FALSE;
348 incomplete(t, "Format[i] != Format[baseLevel]");
349 return;
350 }
351 if (t->Image[0][i]->Border != t->Image[0][baseLevel]->Border) {
352 t->Complete = GL_FALSE;
353 incomplete(t, "Border[i] != Border[baseLevel]");
354 return;
355 }
356 }
357 }
358
359 /* Test things which depend on number of texture image dimensions */
360 if (t->Target == GL_TEXTURE_1D) {
361 /* Test 1-D mipmaps */
362 GLuint width = t->Image[0][baseLevel]->Width2;
363 for (i = baseLevel + 1; i < maxLevels; i++) {
364 if (width > 1) {
365 width /= 2;
366 }
367 if (i >= minLevel && i <= maxLevel) {
368 if (!t->Image[0][i]) {
369 t->Complete = GL_FALSE;
370 incomplete(t, "1D Image[0][i] == NULL");
371 return;
372 }
373 if (t->Image[0][i]->Width2 != width ) {
374 t->Complete = GL_FALSE;
375 incomplete(t, "1D Image[0][i] bad width");
376 return;
377 }
378 }
379 if (width == 1) {
380 return; /* found smallest needed mipmap, all done! */
381 }
382 }
383 }
384 else if (t->Target == GL_TEXTURE_2D) {
385 /* Test 2-D mipmaps */
386 GLuint width = t->Image[0][baseLevel]->Width2;
387 GLuint height = t->Image[0][baseLevel]->Height2;
388 for (i = baseLevel + 1; i < maxLevels; i++) {
389 if (width > 1) {
390 width /= 2;
391 }
392 if (height > 1) {
393 height /= 2;
394 }
395 if (i >= minLevel && i <= maxLevel) {
396 if (!t->Image[0][i]) {
397 t->Complete = GL_FALSE;
398 incomplete(t, "2D Image[0][i] == NULL");
399 return;
400 }
401 if (t->Image[0][i]->Width2 != width) {
402 t->Complete = GL_FALSE;
403 incomplete(t, "2D Image[0][i] bad width");
404 return;
405 }
406 if (t->Image[0][i]->Height2 != height) {
407 t->Complete = GL_FALSE;
408 incomplete(t, "2D Image[0][i] bad height");
409 return;
410 }
411 if (width==1 && height==1) {
412 return; /* found smallest needed mipmap, all done! */
413 }
414 }
415 }
416 }
417 else if (t->Target == GL_TEXTURE_3D) {
418 /* Test 3-D mipmaps */
419 GLuint width = t->Image[0][baseLevel]->Width2;
420 GLuint height = t->Image[0][baseLevel]->Height2;
421 GLuint depth = t->Image[0][baseLevel]->Depth2;
422 for (i = baseLevel + 1; i < maxLevels; i++) {
423 if (width > 1) {
424 width /= 2;
425 }
426 if (height > 1) {
427 height /= 2;
428 }
429 if (depth > 1) {
430 depth /= 2;
431 }
432 if (i >= minLevel && i <= maxLevel) {
433 if (!t->Image[0][i]) {
434 incomplete(t, "3D Image[0][i] == NULL");
435 t->Complete = GL_FALSE;
436 return;
437 }
438 if (t->Image[0][i]->_BaseFormat == GL_DEPTH_COMPONENT) {
439 t->Complete = GL_FALSE;
440 incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex");
441 return;
442 }
443 if (t->Image[0][i]->Width2 != width) {
444 t->Complete = GL_FALSE;
445 incomplete(t, "3D Image[0][i] bad width");
446 return;
447 }
448 if (t->Image[0][i]->Height2 != height) {
449 t->Complete = GL_FALSE;
450 incomplete(t, "3D Image[0][i] bad height");
451 return;
452 }
453 if (t->Image[0][i]->Depth2 != depth) {
454 t->Complete = GL_FALSE;
455 incomplete(t, "3D Image[0][i] bad depth");
456 return;
457 }
458 }
459 if (width == 1 && height == 1 && depth == 1) {
460 return; /* found smallest needed mipmap, all done! */
461 }
462 }
463 }
464 else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
465 /* make sure 6 cube faces are consistant */
466 GLuint width = t->Image[0][baseLevel]->Width2;
467 GLuint height = t->Image[0][baseLevel]->Height2;
468 for (i = baseLevel + 1; i < maxLevels; i++) {
469 if (width > 1) {
470 width /= 2;
471 }
472 if (height > 1) {
473 height /= 2;
474 }
475 if (i >= minLevel && i <= maxLevel) {
476 GLuint face;
477 for (face = 0; face < 6; face++) {
478 /* check that we have images defined */
479 if (!t->Image[face][i]) {
480 t->Complete = GL_FALSE;
481 incomplete(t, "CubeMap Image[n][i] == NULL");
482 return;
483 }
484 /* Don't support GL_DEPTH_COMPONENT for cube maps */
485 if (t->Image[face][i]->_BaseFormat == GL_DEPTH_COMPONENT) {
486 t->Complete = GL_FALSE;
487 incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex");
488 return;
489 }
490 /* check that all six images have same size */
491 if (t->Image[face][i]->Width2!=width ||
492 t->Image[face][i]->Height2!=height) {
493 t->Complete = GL_FALSE;
494 incomplete(t, "CubeMap Image[n][i] bad size");
495 return;
496 }
497 }
498 }
499 if (width == 1 && height == 1) {
500 return; /* found smallest needed mipmap, all done! */
501 }
502 }
503 }
504 else if (t->Target == GL_TEXTURE_RECTANGLE_NV) {
505 /* XXX special checking? */
506 }
507 else {
508 /* Target = ??? */
509 _mesa_problem(ctx, "Bug in gl_test_texture_object_completeness\n");
510 }
511 }
512 }
513
514 /*@}*/
515
516
517 /***********************************************************************/
518 /** \name API functions */
519 /*@{*/
520
521 /**
522 * Texture name generation lock.
523 *
524 * Used by _mesa_GenTextures() to guarantee that the generation and allocation
525 * of texture IDs is atomic.
526 */
527 _glthread_DECLARE_STATIC_MUTEX(GenTexturesLock);
528
529 /**
530 * Generate texture names.
531 *
532 * \param n number of texture names to be generated.
533 * \param textures an array in which will hold the generated texture names.
534 *
535 * \sa glGenTextures().
536 *
537 * While holding the GenTexturesLock lock, calls _mesa_HashFindFreeKeyBlock()
538 * to find a block of free texture IDs which are stored in \p textures.
539 * Corresponding empty texture objects are also generated.
540 */
541 void GLAPIENTRY
542 _mesa_GenTextures( GLsizei n, GLuint *textures )
543 {
544 GET_CURRENT_CONTEXT(ctx);
545 GLuint first;
546 GLint i;
547 ASSERT_OUTSIDE_BEGIN_END(ctx);
548
549 if (n < 0) {
550 _mesa_error( ctx, GL_INVALID_VALUE, "glGenTextures" );
551 return;
552 }
553
554 if (!textures)
555 return;
556
557 /*
558 * This must be atomic (generation and allocation of texture IDs)
559 */
560 _glthread_LOCK_MUTEX(GenTexturesLock);
561
562 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->TexObjects, n);
563
564 /* Allocate new, empty texture objects */
565 for (i = 0; i < n; i++) {
566 struct gl_texture_object *texObj;
567 GLuint name = first + i;
568 GLenum target = 0;
569 texObj = (*ctx->Driver.NewTextureObject)( ctx, name, target);
570 if (!texObj) {
571 _glthread_UNLOCK_MUTEX(GenTexturesLock);
572 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures");
573 return;
574 }
575
576 /* insert into hash table */
577 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
578 _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj);
579 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
580
581 textures[i] = name;
582 }
583
584 _glthread_UNLOCK_MUTEX(GenTexturesLock);
585 }
586
587
588 /**
589 * Delete named textures.
590 *
591 * \param n number of textures to be deleted.
592 * \param textures array of texture IDs to be deleted.
593 *
594 * \sa glDeleteTextures().
595 *
596 * If we're about to delete a texture that's currently bound to any
597 * texture unit, unbind the texture first. Decrement the reference
598 * count on the texture object and delete it if it's zero.
599 * Recall that texture objects can be shared among several rendering
600 * contexts.
601 */
602 void GLAPIENTRY
603 _mesa_DeleteTextures( GLsizei n, const GLuint *textures)
604 {
605 GET_CURRENT_CONTEXT(ctx);
606 GLint i;
607 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */
608
609 if (!textures)
610 return;
611
612 for (i = 0; i < n; i++) {
613 if (textures[i] > 0) {
614 struct gl_texture_object *delObj = (struct gl_texture_object *)
615 _mesa_HashLookup(ctx->Shared->TexObjects, textures[i]);
616 if (delObj) {
617 /* First check if this texture is currently bound.
618 * If so, unbind it and decrement the reference count.
619 * XXX all RefCount accesses should be protected by a mutex.
620 */
621 GLuint u;
622 for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) {
623 struct gl_texture_unit *unit = &ctx->Texture.Unit[u];
624 if (delObj == unit->Current1D) {
625 unit->Current1D = ctx->Shared->Default1D;
626 ctx->Shared->Default1D->RefCount++;
627 delObj->RefCount--;
628 if (delObj == unit->_Current)
629 unit->_Current = unit->Current1D;
630 }
631 else if (delObj == unit->Current2D) {
632 unit->Current2D = ctx->Shared->Default2D;
633 ctx->Shared->Default2D->RefCount++;
634 delObj->RefCount--;
635 if (delObj == unit->_Current)
636 unit->_Current = unit->Current2D;
637 }
638 else if (delObj == unit->Current3D) {
639 unit->Current3D = ctx->Shared->Default3D;
640 ctx->Shared->Default3D->RefCount++;
641 delObj->RefCount--;
642 if (delObj == unit->_Current)
643 unit->_Current = unit->Current3D;
644 }
645 else if (delObj == unit->CurrentCubeMap) {
646 unit->CurrentCubeMap = ctx->Shared->DefaultCubeMap;
647 ctx->Shared->DefaultCubeMap->RefCount++;
648 delObj->RefCount--;
649 if (delObj == unit->_Current)
650 unit->_Current = unit->CurrentCubeMap;
651 }
652 else if (delObj == unit->CurrentRect) {
653 unit->CurrentRect = ctx->Shared->DefaultRect;
654 ctx->Shared->DefaultRect->RefCount++;
655 delObj->RefCount--;
656 if (delObj == unit->_Current)
657 unit->_Current = unit->CurrentRect;
658 }
659 }
660 ctx->NewState |= _NEW_TEXTURE;
661
662 /* The texture _name_ is now free for re-use.
663 * Remove it from the hash table now.
664 */
665 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
666 _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name);
667 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
668
669 /* The actual texture object will not be freed until it's no
670 * longer bound in any context.
671 * XXX all RefCount accesses should be protected by a mutex.
672 */
673 delObj->RefCount--;
674 if (delObj->RefCount == 0) {
675 ASSERT(delObj->Name != 0); /* Never delete default tex objs */
676 ASSERT(ctx->Driver.DeleteTexture);
677 (*ctx->Driver.DeleteTexture)(ctx, delObj);
678 }
679 }
680 }
681 }
682 }
683
684
685 /**
686 * Bind a named texture to a texturing target.
687 *
688 * \param target texture target.
689 * \param texName texture name.
690 *
691 * \sa glBindTexture().
692 *
693 * Determines the old texture object bound and returns immediately if rebinding
694 * the same texture. Get the current texture which is either a default texture
695 * if name is null, a named texture from the hash, or a new texture if the
696 * given texture name is new. Increments its reference count, binds it, and
697 * calls dd_function_table::BindTexture. Decrements the old texture reference
698 * count and deletes it if it reaches zero.
699 */
700 void GLAPIENTRY
701 _mesa_BindTexture( GLenum target, GLuint texName )
702 {
703 GET_CURRENT_CONTEXT(ctx);
704 GLuint unit = ctx->Texture.CurrentUnit;
705 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
706 struct gl_texture_object *oldTexObj;
707 struct gl_texture_object *newTexObj = NULL;
708 ASSERT_OUTSIDE_BEGIN_END(ctx);
709
710 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
711 _mesa_debug(ctx, "glBindTexture %s %d\n",
712 _mesa_lookup_enum_by_nr(target), (GLint) texName);
713
714 /*
715 * Get pointer to currently bound texture object (oldTexObj)
716 */
717 switch (target) {
718 case GL_TEXTURE_1D:
719 oldTexObj = texUnit->Current1D;
720 break;
721 case GL_TEXTURE_2D:
722 oldTexObj = texUnit->Current2D;
723 break;
724 case GL_TEXTURE_3D:
725 oldTexObj = texUnit->Current3D;
726 break;
727 case GL_TEXTURE_CUBE_MAP_ARB:
728 if (!ctx->Extensions.ARB_texture_cube_map) {
729 _mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" );
730 return;
731 }
732 oldTexObj = texUnit->CurrentCubeMap;
733 break;
734 case GL_TEXTURE_RECTANGLE_NV:
735 if (!ctx->Extensions.NV_texture_rectangle) {
736 _mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" );
737 return;
738 }
739 oldTexObj = texUnit->CurrentRect;
740 break;
741 default:
742 _mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" );
743 return;
744 }
745
746 if (oldTexObj->Name == texName)
747 /* XXX this might be wrong. If the texobj is in use by another
748 * context and a texobj parameter was changed, this might be our
749 * only chance to update this context's hardware state.
750 */
751 return; /* rebinding the same texture- no change */
752
753 /*
754 * Get pointer to new texture object (newTexObj)
755 */
756 if (texName == 0) {
757 /* newTexObj = a default texture object */
758 switch (target) {
759 case GL_TEXTURE_1D:
760 newTexObj = ctx->Shared->Default1D;
761 break;
762 case GL_TEXTURE_2D:
763 newTexObj = ctx->Shared->Default2D;
764 break;
765 case GL_TEXTURE_3D:
766 newTexObj = ctx->Shared->Default3D;
767 break;
768 case GL_TEXTURE_CUBE_MAP_ARB:
769 newTexObj = ctx->Shared->DefaultCubeMap;
770 break;
771 case GL_TEXTURE_RECTANGLE_NV:
772 newTexObj = ctx->Shared->DefaultRect;
773 break;
774 default:
775 ; /* Bad targets are caught above */
776 }
777 }
778 else {
779 /* non-default texture object */
780 const struct _mesa_HashTable *hash = ctx->Shared->TexObjects;
781 newTexObj = (struct gl_texture_object *) _mesa_HashLookup(hash, texName);
782 if (newTexObj) {
783 /* error checking */
784 if (newTexObj->Target != 0 && newTexObj->Target != target) {
785 /* the named texture object's dimensions don't match the target */
786 _mesa_error( ctx, GL_INVALID_OPERATION,
787 "glBindTexture(wrong dimensionality)" );
788 return;
789 }
790 if (newTexObj->Target == 0 && target == GL_TEXTURE_RECTANGLE_NV) {
791 /* have to init wrap and filter state here - kind of klunky */
792 newTexObj->WrapS = GL_CLAMP_TO_EDGE;
793 newTexObj->WrapT = GL_CLAMP_TO_EDGE;
794 newTexObj->WrapR = GL_CLAMP_TO_EDGE;
795 newTexObj->MinFilter = GL_LINEAR;
796 if (ctx->Driver.TexParameter) {
797 static const GLfloat fparam_wrap[1] = {(GLfloat) GL_CLAMP_TO_EDGE};
798 static const GLfloat fparam_filter[1] = {(GLfloat) GL_LINEAR};
799 (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_WRAP_S, fparam_wrap );
800 (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_WRAP_T, fparam_wrap );
801 (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_WRAP_R, fparam_wrap );
802 (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_MIN_FILTER, fparam_filter );
803 }
804 }
805 }
806 else {
807 /* if this is a new texture id, allocate a texture object now */
808 newTexObj = (*ctx->Driver.NewTextureObject)(ctx, texName, target);
809 if (!newTexObj) {
810 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture");
811 return;
812 }
813
814 /* and insert it into hash table */
815 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
816 _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj);
817 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
818 }
819 newTexObj->Target = target;
820 }
821
822 /* XXX all RefCount accesses should be protected by a mutex. */
823 newTexObj->RefCount++;
824
825 /* do the actual binding, but first flush outstanding vertices:
826 */
827 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
828
829 switch (target) {
830 case GL_TEXTURE_1D:
831 texUnit->Current1D = newTexObj;
832 break;
833 case GL_TEXTURE_2D:
834 texUnit->Current2D = newTexObj;
835 break;
836 case GL_TEXTURE_3D:
837 texUnit->Current3D = newTexObj;
838 break;
839 case GL_TEXTURE_CUBE_MAP_ARB:
840 texUnit->CurrentCubeMap = newTexObj;
841 break;
842 case GL_TEXTURE_RECTANGLE_NV:
843 texUnit->CurrentRect = newTexObj;
844 break;
845 default:
846 _mesa_problem(ctx, "bad target in BindTexture");
847 return;
848 }
849
850 /* Pass BindTexture call to device driver */
851 if (ctx->Driver.BindTexture)
852 (*ctx->Driver.BindTexture)( ctx, target, newTexObj );
853
854 /* Decrement the reference count on the old texture and check if it's
855 * time to delete it.
856 */
857 /* XXX all RefCount accesses should be protected by a mutex. */
858 oldTexObj->RefCount--;
859 ASSERT(oldTexObj->RefCount >= 0);
860 if (oldTexObj->RefCount == 0) {
861 ASSERT(oldTexObj->Name != 0);
862 ASSERT(ctx->Driver.DeleteTexture);
863 (*ctx->Driver.DeleteTexture)( ctx, oldTexObj );
864 }
865 }
866
867
868 /**
869 * Set texture priorities.
870 *
871 * \param n number of textures.
872 * \param texName texture names.
873 * \param priorities corresponding texture priorities.
874 *
875 * \sa glPrioritizeTextures().
876 *
877 * Looks up each texture in the hash, clamps the corresponding priority between
878 * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture.
879 */
880 void GLAPIENTRY
881 _mesa_PrioritizeTextures( GLsizei n, const GLuint *texName,
882 const GLclampf *priorities )
883 {
884 GET_CURRENT_CONTEXT(ctx);
885 GLint i;
886 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
887
888 if (n < 0) {
889 _mesa_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" );
890 return;
891 }
892
893 if (!priorities)
894 return;
895
896 for (i = 0; i < n; i++) {
897 if (texName[i] > 0) {
898 struct gl_texture_object *t = (struct gl_texture_object *)
899 _mesa_HashLookup(ctx->Shared->TexObjects, texName[i]);
900 if (t) {
901 t->Priority = CLAMP( priorities[i], 0.0F, 1.0F );
902 if (ctx->Driver.PrioritizeTexture)
903 ctx->Driver.PrioritizeTexture( ctx, t, t->Priority );
904 }
905 }
906 }
907
908 ctx->NewState |= _NEW_TEXTURE;
909 }
910
911 /**
912 * See if textures are loaded in texture memory.
913 *
914 * \param n number of textures to query.
915 * \param texName array with the texture names.
916 * \param residences array which will hold the residence status.
917 *
918 * \return GL_TRUE if all textures are resident and \p residences is left unchanged,
919 *
920 * \sa glAreTexturesResident().
921 *
922 * Looks up each texture in the hash and calls
923 * dd_function_table::IsTextureResident.
924 */
925 GLboolean GLAPIENTRY
926 _mesa_AreTexturesResident(GLsizei n, const GLuint *texName,
927 GLboolean *residences)
928 {
929 GET_CURRENT_CONTEXT(ctx);
930 GLboolean allResident = GL_TRUE;
931 GLint i, j;
932 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
933
934 if (n < 0) {
935 _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)");
936 return GL_FALSE;
937 }
938
939 if (!texName || !residences)
940 return GL_FALSE;
941
942 for (i = 0; i < n; i++) {
943 struct gl_texture_object *t;
944 if (texName[i] == 0) {
945 _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident");
946 return GL_FALSE;
947 }
948 t = (struct gl_texture_object *)
949 _mesa_HashLookup(ctx->Shared->TexObjects, texName[i]);
950 if (!t) {
951 _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident");
952 return GL_FALSE;
953 }
954 if (!ctx->Driver.IsTextureResident ||
955 ctx->Driver.IsTextureResident(ctx, t)) {
956 /* The texture is resident */
957 if (!allResident)
958 residences[i] = GL_TRUE;
959 }
960 else {
961 /* The texture is not resident */
962 if (allResident) {
963 allResident = GL_FALSE;
964 for (j = 0; j < i; j++)
965 residences[j] = GL_TRUE;
966 }
967 residences[i] = GL_FALSE;
968 }
969 }
970
971 return allResident;
972 }
973
974 /**
975 * See if a name corresponds to a texture.
976 *
977 * \param texture texture name.
978 *
979 * \return GL_TRUE if texture name corresponds to a texture, or GL_FALSE
980 * otherwise.
981 *
982 * \sa glIsTexture().
983 *
984 * Calls _mesa_HashLookup().
985 */
986 GLboolean GLAPIENTRY
987 _mesa_IsTexture( GLuint texture )
988 {
989 struct gl_texture_object *t;
990 GET_CURRENT_CONTEXT(ctx);
991 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
992
993 if (!texture)
994 return GL_FALSE;
995
996 t = (struct gl_texture_object *)
997 _mesa_HashLookup(ctx->Shared->TexObjects, texture);
998
999 /* IsTexture is true only after object has been bound once. */
1000 return t && t->Target;
1001 }
1002
1003 /*@}*/