59a1d9375ff0f98ea33c364b995380643928046a
3 * Texture object management.
7 * Mesa 3-D graphics library
10 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
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:
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
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.
46 #define _mesa_sprintf sprintf
49 /**********************************************************************/
50 /** \name Internal functions */
54 * Allocate and initialize a new texture object. But don't put it into the
55 * texture object hash table.
57 * Called via ctx->Driver.NewTextureObject, unless overridden by a device
60 * \param shared the shared GL state structure to contain the texture object
61 * \param name integer name for the texture object
62 * \param target either GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D,
63 * GL_TEXTURE_CUBE_MAP_ARB or GL_TEXTURE_RECTANGLE_NV. zero is ok for the sake
66 * \return pointer to new texture object.
68 struct gl_texture_object
*
69 _mesa_new_texture_object( GLcontext
*ctx
, GLuint name
, GLenum target
)
71 struct gl_texture_object
*obj
;
73 obj
= MALLOC_STRUCT(gl_texture_object
);
74 _mesa_initialize_texture_object(obj
, name
, target
);
80 * Initialize a new texture object to default values.
81 * \param obj the texture object
82 * \param name the texture name
83 * \param target the texture target
86 _mesa_initialize_texture_object( struct gl_texture_object
*obj
,
87 GLuint name
, GLenum target
)
90 target
== GL_TEXTURE_1D
||
91 target
== GL_TEXTURE_2D
||
92 target
== GL_TEXTURE_3D
||
93 target
== GL_TEXTURE_CUBE_MAP_ARB
||
94 target
== GL_TEXTURE_RECTANGLE_NV
);
96 _mesa_bzero(obj
, sizeof(*obj
));
97 /* init the non-zero fields */
98 _glthread_INIT_MUTEX(obj
->Mutex
);
101 obj
->Target
= target
;
102 obj
->Priority
= 1.0F
;
103 if (target
== GL_TEXTURE_RECTANGLE_NV
) {
104 obj
->WrapS
= GL_CLAMP_TO_EDGE
;
105 obj
->WrapT
= GL_CLAMP_TO_EDGE
;
106 obj
->WrapR
= GL_CLAMP_TO_EDGE
;
107 obj
->MinFilter
= GL_LINEAR
;
110 obj
->WrapS
= GL_REPEAT
;
111 obj
->WrapT
= GL_REPEAT
;
112 obj
->WrapR
= GL_REPEAT
;
113 obj
->MinFilter
= GL_NEAREST_MIPMAP_LINEAR
;
115 obj
->MagFilter
= GL_LINEAR
;
116 obj
->MinLod
= -1000.0;
117 obj
->MaxLod
= 1000.0;
120 obj
->MaxLevel
= 1000;
121 obj
->MaxAnisotropy
= 1.0;
122 obj
->CompareFlag
= GL_FALSE
; /* SGIX_shadow */
123 obj
->CompareOperator
= GL_TEXTURE_LEQUAL_R_SGIX
; /* SGIX_shadow */
124 obj
->CompareMode
= GL_NONE
; /* ARB_shadow */
125 obj
->CompareFunc
= GL_LEQUAL
; /* ARB_shadow */
126 obj
->DepthMode
= GL_LUMINANCE
; /* ARB_depth_texture */
127 obj
->ShadowAmbient
= 0.0F
; /* ARB/SGIX_shadow_ambient */
128 _mesa_init_colortable(&obj
->Palette
);
133 * Deallocate a texture object struct. It should have already been
134 * removed from the texture object pool.
136 * \param shared the shared GL state to which the object belongs.
137 * \param texOjb the texture object to delete.
140 _mesa_delete_texture_object( GLcontext
*ctx
, struct gl_texture_object
*texObj
)
146 _mesa_free_colortable_data(&texObj
->Palette
);
148 /* free the texture images */
149 for (face
= 0; face
< 6; face
++) {
150 for (i
= 0; i
< MAX_TEXTURE_LEVELS
; i
++) {
151 if (texObj
->Image
[face
][i
]) {
152 _mesa_delete_texture_image( ctx
, texObj
->Image
[face
][i
] );
157 /* destroy the mutex -- it may have allocated memory (eg on bsd) */
158 _glthread_DESTROY_MUTEX(texObj
->Mutex
);
160 /* free this object */
168 * Copy texture object state from one texture object to another.
169 * Use for glPush/PopAttrib.
171 * \param dest destination texture object.
172 * \param src source texture object.
175 _mesa_copy_texture_object( struct gl_texture_object
*dest
,
176 const struct gl_texture_object
*src
)
178 dest
->Name
= src
->Name
;
179 dest
->Priority
= src
->Priority
;
180 dest
->BorderColor
[0] = src
->BorderColor
[0];
181 dest
->BorderColor
[1] = src
->BorderColor
[1];
182 dest
->BorderColor
[2] = src
->BorderColor
[2];
183 dest
->BorderColor
[3] = src
->BorderColor
[3];
184 dest
->WrapS
= src
->WrapS
;
185 dest
->WrapT
= src
->WrapT
;
186 dest
->WrapR
= src
->WrapR
;
187 dest
->MinFilter
= src
->MinFilter
;
188 dest
->MagFilter
= src
->MagFilter
;
189 dest
->MinLod
= src
->MinLod
;
190 dest
->MaxLod
= src
->MaxLod
;
191 dest
->LodBias
= src
->LodBias
;
192 dest
->BaseLevel
= src
->BaseLevel
;
193 dest
->MaxLevel
= src
->MaxLevel
;
194 dest
->MaxAnisotropy
= src
->MaxAnisotropy
;
195 dest
->CompareFlag
= src
->CompareFlag
;
196 dest
->CompareOperator
= src
->CompareOperator
;
197 dest
->ShadowAmbient
= src
->ShadowAmbient
;
198 dest
->CompareMode
= src
->CompareMode
;
199 dest
->CompareFunc
= src
->CompareFunc
;
200 dest
->DepthMode
= src
->DepthMode
;
201 dest
->_MaxLevel
= src
->_MaxLevel
;
202 dest
->_MaxLambda
= src
->_MaxLambda
;
203 dest
->GenerateMipmap
= src
->GenerateMipmap
;
204 dest
->Palette
= src
->Palette
;
205 dest
->Complete
= src
->Complete
;
210 * Report why a texture object is incomplete.
212 * \param t texture object.
213 * \param why string describing why it's incomplete.
215 * \note For debug purposes only.
219 incomplete(const struct gl_texture_object
*t
, const char *why
)
221 _mesa_printf("Texture Obj %d incomplete because: %s\n", t
->Name
, why
);
224 #define incomplete(t, why)
229 * Examine a texture object to determine if it is complete.
231 * The gl_texture_object::Complete flag will be set to GL_TRUE or GL_FALSE
234 * \param ctx GL context.
235 * \param t texture object.
237 * According to the texture target, verifies that each of the mipmaps is
238 * present and has the expected size.
241 _mesa_test_texobj_completeness( const GLcontext
*ctx
,
242 struct gl_texture_object
*t
)
244 const GLint baseLevel
= t
->BaseLevel
;
245 GLint maxLog2
= 0, maxLevels
= 0;
247 t
->Complete
= GL_TRUE
; /* be optimistic */
249 /* Always need the base level image */
250 if (!t
->Image
[0][baseLevel
]) {
252 _mesa_sprintf(s
, "obj %p (%d) Image[baseLevel=%d] == NULL",
253 (void *) t
, t
->Name
, baseLevel
);
255 t
->Complete
= GL_FALSE
;
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
;
268 /* Compute _MaxLevel */
269 if (t
->Target
== GL_TEXTURE_1D
) {
270 maxLog2
= t
->Image
[0][baseLevel
]->WidthLog2
;
271 maxLevels
= ctx
->Const
.MaxTextureLevels
;
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
;
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
;
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
;
289 else if (t
->Target
== GL_TEXTURE_RECTANGLE_NV
) {
290 maxLog2
= 0; /* not applicable */
291 maxLevels
= 1; /* no mipmapping */
294 _mesa_problem(ctx
, "Bad t->Target in _mesa_test_texobj_completeness");
298 ASSERT(maxLevels
> 0);
300 t
->_MaxLevel
= baseLevel
+ maxLog2
;
301 t
->_MaxLevel
= MIN2(t
->_MaxLevel
, t
->MaxLevel
);
302 t
->_MaxLevel
= MIN2(t
->_MaxLevel
, maxLevels
- 1);
304 /* Compute _MaxLambda = q - b (see the 1.2 spec) used during mipmapping */
305 t
->_MaxLambda
= (GLfloat
) (t
->_MaxLevel
- t
->BaseLevel
);
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
;
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");
323 /* extra checking for mipmaps */
324 if (t
->MinFilter
!= GL_NEAREST
&& t
->MinFilter
!= GL_LINEAR
) {
326 * Mipmapping: determine if we have a complete set of mipmaps
329 GLint minLevel
= baseLevel
;
330 GLint maxLevel
= t
->_MaxLevel
;
332 if (minLevel
> maxLevel
) {
333 t
->Complete
= GL_FALSE
;
334 incomplete(t
, "minLevel > maxLevel");
338 /* Test dimension-independent attributes */
339 for (i
= minLevel
; i
<= maxLevel
; i
++) {
340 if (t
->Image
[0][i
]) {
341 if (t
->Image
[0][i
]->TexFormat
!= t
->Image
[0][baseLevel
]->TexFormat
) {
342 t
->Complete
= GL_FALSE
;
343 incomplete(t
, "Format[i] != Format[baseLevel]");
346 if (t
->Image
[0][i
]->Border
!= t
->Image
[0][baseLevel
]->Border
) {
347 t
->Complete
= GL_FALSE
;
348 incomplete(t
, "Border[i] != Border[baseLevel]");
354 /* Test things which depend on number of texture image dimensions */
355 if (t
->Target
== GL_TEXTURE_1D
) {
356 /* Test 1-D mipmaps */
357 GLuint width
= t
->Image
[0][baseLevel
]->Width2
;
358 for (i
= baseLevel
+ 1; i
< maxLevels
; i
++) {
362 if (i
>= minLevel
&& i
<= maxLevel
) {
363 if (!t
->Image
[0][i
]) {
364 t
->Complete
= GL_FALSE
;
365 incomplete(t
, "1D Image[0][i] == NULL");
368 if (t
->Image
[0][i
]->Width2
!= width
) {
369 t
->Complete
= GL_FALSE
;
370 incomplete(t
, "1D Image[0][i] bad width");
375 return; /* found smallest needed mipmap, all done! */
379 else if (t
->Target
== GL_TEXTURE_2D
) {
380 /* Test 2-D mipmaps */
381 GLuint width
= t
->Image
[0][baseLevel
]->Width2
;
382 GLuint height
= t
->Image
[0][baseLevel
]->Height2
;
383 for (i
= baseLevel
+ 1; i
< maxLevels
; i
++) {
390 if (i
>= minLevel
&& i
<= maxLevel
) {
391 if (!t
->Image
[0][i
]) {
392 t
->Complete
= GL_FALSE
;
393 incomplete(t
, "2D Image[0][i] == NULL");
396 if (t
->Image
[0][i
]->Width2
!= width
) {
397 t
->Complete
= GL_FALSE
;
398 incomplete(t
, "2D Image[0][i] bad width");
401 if (t
->Image
[0][i
]->Height2
!= height
) {
402 t
->Complete
= GL_FALSE
;
403 incomplete(t
, "2D Image[0][i] bad height");
406 if (width
==1 && height
==1) {
407 return; /* found smallest needed mipmap, all done! */
412 else if (t
->Target
== GL_TEXTURE_3D
) {
413 /* Test 3-D mipmaps */
414 GLuint width
= t
->Image
[0][baseLevel
]->Width2
;
415 GLuint height
= t
->Image
[0][baseLevel
]->Height2
;
416 GLuint depth
= t
->Image
[0][baseLevel
]->Depth2
;
417 for (i
= baseLevel
+ 1; i
< maxLevels
; i
++) {
427 if (i
>= minLevel
&& i
<= maxLevel
) {
428 if (!t
->Image
[0][i
]) {
429 incomplete(t
, "3D Image[0][i] == NULL");
430 t
->Complete
= GL_FALSE
;
433 if (t
->Image
[0][i
]->_BaseFormat
== GL_DEPTH_COMPONENT
) {
434 t
->Complete
= GL_FALSE
;
435 incomplete(t
, "GL_DEPTH_COMPONENT only works with 1/2D tex");
438 if (t
->Image
[0][i
]->Width2
!= width
) {
439 t
->Complete
= GL_FALSE
;
440 incomplete(t
, "3D Image[0][i] bad width");
443 if (t
->Image
[0][i
]->Height2
!= height
) {
444 t
->Complete
= GL_FALSE
;
445 incomplete(t
, "3D Image[0][i] bad height");
448 if (t
->Image
[0][i
]->Depth2
!= depth
) {
449 t
->Complete
= GL_FALSE
;
450 incomplete(t
, "3D Image[0][i] bad depth");
454 if (width
== 1 && height
== 1 && depth
== 1) {
455 return; /* found smallest needed mipmap, all done! */
459 else if (t
->Target
== GL_TEXTURE_CUBE_MAP_ARB
) {
460 /* make sure 6 cube faces are consistant */
461 GLuint width
= t
->Image
[0][baseLevel
]->Width2
;
462 GLuint height
= t
->Image
[0][baseLevel
]->Height2
;
463 for (i
= baseLevel
+ 1; i
< maxLevels
; i
++) {
470 if (i
>= minLevel
&& i
<= maxLevel
) {
472 for (face
= 0; face
< 6; face
++) {
473 /* check that we have images defined */
474 if (!t
->Image
[face
][i
]) {
475 t
->Complete
= GL_FALSE
;
476 incomplete(t
, "CubeMap Image[n][i] == NULL");
479 /* Don't support GL_DEPTH_COMPONENT for cube maps */
480 if (t
->Image
[face
][i
]->_BaseFormat
== GL_DEPTH_COMPONENT
) {
481 t
->Complete
= GL_FALSE
;
482 incomplete(t
, "GL_DEPTH_COMPONENT only works with 1/2D tex");
485 /* check that all six images have same size */
486 if (t
->Image
[face
][i
]->Width2
!=width
||
487 t
->Image
[face
][i
]->Height2
!=height
) {
488 t
->Complete
= GL_FALSE
;
489 incomplete(t
, "CubeMap Image[n][i] bad size");
494 if (width
== 1 && height
== 1) {
495 return; /* found smallest needed mipmap, all done! */
499 else if (t
->Target
== GL_TEXTURE_RECTANGLE_NV
) {
500 /* XXX special checking? */
504 _mesa_problem(ctx
, "Bug in gl_test_texture_object_completeness\n");
512 /***********************************************************************/
513 /** \name API functions */
517 * Texture name generation lock.
519 * Used by _mesa_GenTextures() to guarantee that the generation and allocation
520 * of texture IDs is atomic.
522 _glthread_DECLARE_STATIC_MUTEX(GenTexturesLock
);
525 * Generate texture names.
527 * \param n number of texture names to be generated.
528 * \param textures an array in which will hold the generated texture names.
530 * \sa glGenTextures().
532 * While holding the GenTexturesLock lock, calls _mesa_HashFindFreeKeyBlock()
533 * to find a block of free texture IDs which are stored in \p textures.
534 * Corresponding empty texture objects are also generated.
537 _mesa_GenTextures( GLsizei n
, GLuint
*textures
)
539 GET_CURRENT_CONTEXT(ctx
);
542 ASSERT_OUTSIDE_BEGIN_END(ctx
);
545 _mesa_error( ctx
, GL_INVALID_VALUE
, "glGenTextures" );
553 * This must be atomic (generation and allocation of texture IDs)
555 _glthread_LOCK_MUTEX(GenTexturesLock
);
557 first
= _mesa_HashFindFreeKeyBlock(ctx
->Shared
->TexObjects
, n
);
559 /* Allocate new, empty texture objects */
560 for (i
= 0; i
< n
; i
++) {
561 struct gl_texture_object
*texObj
;
562 GLuint name
= first
+ i
;
564 texObj
= (*ctx
->Driver
.NewTextureObject
)( ctx
, name
, target
);
566 _glthread_UNLOCK_MUTEX(GenTexturesLock
);
567 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGenTextures");
571 /* insert into hash table */
572 _glthread_LOCK_MUTEX(ctx
->Shared
->Mutex
);
573 _mesa_HashInsert(ctx
->Shared
->TexObjects
, texObj
->Name
, texObj
);
574 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
579 _glthread_UNLOCK_MUTEX(GenTexturesLock
);
584 * Check if the given texture object is bound to the current draw or
585 * read framebuffer. If so, Unbind it.
588 unbind_texobj_from_fbo(GLcontext
*ctx
, struct gl_texture_object
*texObj
)
590 const GLuint n
= (ctx
->DrawBuffer
== ctx
->ReadBuffer
) ? 1 : 2;
593 for (i
= 0; i
< n
; i
++) {
594 struct gl_framebuffer
*fb
= (i
== 0) ? ctx
->DrawBuffer
: ctx
->ReadBuffer
;
597 for (j
= 0; j
< BUFFER_COUNT
; j
++) {
598 if (fb
->Attachment
[j
].Type
== GL_TEXTURE
&&
599 fb
->Attachment
[j
].Texture
== texObj
) {
600 _mesa_remove_attachment(ctx
, fb
->Attachment
+ j
);
609 * Check if the given texture object is bound to any texture image units and
611 * XXX all RefCount accesses should be protected by a mutex.
614 unbind_texobj_from_texunits(GLcontext
*ctx
, struct gl_texture_object
*texObj
)
618 for (u
= 0; u
< MAX_TEXTURE_IMAGE_UNITS
; u
++) {
619 struct gl_texture_unit
*unit
= &ctx
->Texture
.Unit
[u
];
620 if (texObj
== unit
->Current1D
) {
621 unit
->Current1D
= ctx
->Shared
->Default1D
;
622 ctx
->Shared
->Default1D
->RefCount
++;
624 if (texObj
== unit
->_Current
)
625 unit
->_Current
= unit
->Current1D
;
627 else if (texObj
== unit
->Current2D
) {
628 unit
->Current2D
= ctx
->Shared
->Default2D
;
629 ctx
->Shared
->Default2D
->RefCount
++;
631 if (texObj
== unit
->_Current
)
632 unit
->_Current
= unit
->Current2D
;
634 else if (texObj
== unit
->Current3D
) {
635 unit
->Current3D
= ctx
->Shared
->Default3D
;
636 ctx
->Shared
->Default3D
->RefCount
++;
638 if (texObj
== unit
->_Current
)
639 unit
->_Current
= unit
->Current3D
;
641 else if (texObj
== unit
->CurrentCubeMap
) {
642 unit
->CurrentCubeMap
= ctx
->Shared
->DefaultCubeMap
;
643 ctx
->Shared
->DefaultCubeMap
->RefCount
++;
645 if (texObj
== unit
->_Current
)
646 unit
->_Current
= unit
->CurrentCubeMap
;
648 else if (texObj
== unit
->CurrentRect
) {
649 unit
->CurrentRect
= ctx
->Shared
->DefaultRect
;
650 ctx
->Shared
->DefaultRect
->RefCount
++;
652 if (texObj
== unit
->_Current
)
653 unit
->_Current
= unit
->CurrentRect
;
660 * Delete named textures.
662 * \param n number of textures to be deleted.
663 * \param textures array of texture IDs to be deleted.
665 * \sa glDeleteTextures().
667 * If we're about to delete a texture that's currently bound to any
668 * texture unit, unbind the texture first. Decrement the reference
669 * count on the texture object and delete it if it's zero.
670 * Recall that texture objects can be shared among several rendering
674 _mesa_DeleteTextures( GLsizei n
, const GLuint
*textures
)
676 GET_CURRENT_CONTEXT(ctx
);
678 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
); /* too complex */
683 for (i
= 0; i
< n
; i
++) {
684 if (textures
[i
] > 0) {
685 struct gl_texture_object
*delObj
= (struct gl_texture_object
*)
686 _mesa_HashLookup(ctx
->Shared
->TexObjects
, textures
[i
]);
689 /* Check if texture is bound to any framebuffer objects.
691 * See section 4.4.2.3 of GL_EXT_framebuffer_object.
693 unbind_texobj_from_fbo(ctx
, delObj
);
695 /* Check if this texture is currently bound to any texture units.
696 * If so, unbind it and decrement the reference count.
698 unbind_texobj_from_texunits(ctx
, delObj
);
700 ctx
->NewState
|= _NEW_TEXTURE
;
702 /* The texture _name_ is now free for re-use.
703 * Remove it from the hash table now.
705 _glthread_LOCK_MUTEX(ctx
->Shared
->Mutex
);
706 _mesa_HashRemove(ctx
->Shared
->TexObjects
, delObj
->Name
);
707 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
709 /* The actual texture object will not be freed until it's no
710 * longer bound in any context.
711 * XXX all RefCount accesses should be protected by a mutex.
714 if (delObj
->RefCount
== 0) {
715 ASSERT(delObj
->Name
!= 0); /* Never delete default tex objs */
716 ASSERT(ctx
->Driver
.DeleteTexture
);
717 (*ctx
->Driver
.DeleteTexture
)(ctx
, delObj
);
726 * Bind a named texture to a texturing target.
728 * \param target texture target.
729 * \param texName texture name.
731 * \sa glBindTexture().
733 * Determines the old texture object bound and returns immediately if rebinding
734 * the same texture. Get the current texture which is either a default texture
735 * if name is null, a named texture from the hash, or a new texture if the
736 * given texture name is new. Increments its reference count, binds it, and
737 * calls dd_function_table::BindTexture. Decrements the old texture reference
738 * count and deletes it if it reaches zero.
741 _mesa_BindTexture( GLenum target
, GLuint texName
)
743 GET_CURRENT_CONTEXT(ctx
);
744 GLuint unit
= ctx
->Texture
.CurrentUnit
;
745 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[unit
];
746 struct gl_texture_object
*oldTexObj
;
747 struct gl_texture_object
*newTexObj
= NULL
;
748 ASSERT_OUTSIDE_BEGIN_END(ctx
);
750 if (MESA_VERBOSE
& (VERBOSE_API
|VERBOSE_TEXTURE
))
751 _mesa_debug(ctx
, "glBindTexture %s %d\n",
752 _mesa_lookup_enum_by_nr(target
), (GLint
) texName
);
755 * Get pointer to currently bound texture object (oldTexObj)
759 oldTexObj
= texUnit
->Current1D
;
762 oldTexObj
= texUnit
->Current2D
;
765 oldTexObj
= texUnit
->Current3D
;
767 case GL_TEXTURE_CUBE_MAP_ARB
:
768 if (!ctx
->Extensions
.ARB_texture_cube_map
) {
769 _mesa_error( ctx
, GL_INVALID_ENUM
, "glBindTexture(target)" );
772 oldTexObj
= texUnit
->CurrentCubeMap
;
774 case GL_TEXTURE_RECTANGLE_NV
:
775 if (!ctx
->Extensions
.NV_texture_rectangle
) {
776 _mesa_error( ctx
, GL_INVALID_ENUM
, "glBindTexture(target)" );
779 oldTexObj
= texUnit
->CurrentRect
;
782 _mesa_error( ctx
, GL_INVALID_ENUM
, "glBindTexture(target)" );
786 if (oldTexObj
->Name
== texName
)
787 /* XXX this might be wrong. If the texobj is in use by another
788 * context and a texobj parameter was changed, this might be our
789 * only chance to update this context's hardware state.
791 return; /* rebinding the same texture- no change */
794 * Get pointer to new texture object (newTexObj)
797 /* newTexObj = a default texture object */
800 newTexObj
= ctx
->Shared
->Default1D
;
803 newTexObj
= ctx
->Shared
->Default2D
;
806 newTexObj
= ctx
->Shared
->Default3D
;
808 case GL_TEXTURE_CUBE_MAP_ARB
:
809 newTexObj
= ctx
->Shared
->DefaultCubeMap
;
811 case GL_TEXTURE_RECTANGLE_NV
:
812 newTexObj
= ctx
->Shared
->DefaultRect
;
815 ; /* Bad targets are caught above */
819 /* non-default texture object */
820 const struct _mesa_HashTable
*hash
= ctx
->Shared
->TexObjects
;
821 newTexObj
= (struct gl_texture_object
*) _mesa_HashLookup(hash
, texName
);
824 if (newTexObj
->Target
!= 0 && newTexObj
->Target
!= target
) {
825 /* the named texture object's dimensions don't match the target */
826 _mesa_error( ctx
, GL_INVALID_OPERATION
,
827 "glBindTexture(wrong dimensionality)" );
830 if (newTexObj
->Target
== 0 && target
== GL_TEXTURE_RECTANGLE_NV
) {
831 /* have to init wrap and filter state here - kind of klunky */
832 newTexObj
->WrapS
= GL_CLAMP_TO_EDGE
;
833 newTexObj
->WrapT
= GL_CLAMP_TO_EDGE
;
834 newTexObj
->WrapR
= GL_CLAMP_TO_EDGE
;
835 newTexObj
->MinFilter
= GL_LINEAR
;
836 if (ctx
->Driver
.TexParameter
) {
837 static const GLfloat fparam_wrap
[1] = {(GLfloat
) GL_CLAMP_TO_EDGE
};
838 static const GLfloat fparam_filter
[1] = {(GLfloat
) GL_LINEAR
};
839 (*ctx
->Driver
.TexParameter
)( ctx
, target
, newTexObj
, GL_TEXTURE_WRAP_S
, fparam_wrap
);
840 (*ctx
->Driver
.TexParameter
)( ctx
, target
, newTexObj
, GL_TEXTURE_WRAP_T
, fparam_wrap
);
841 (*ctx
->Driver
.TexParameter
)( ctx
, target
, newTexObj
, GL_TEXTURE_WRAP_R
, fparam_wrap
);
842 (*ctx
->Driver
.TexParameter
)( ctx
, target
, newTexObj
, GL_TEXTURE_MIN_FILTER
, fparam_filter
);
847 /* if this is a new texture id, allocate a texture object now */
848 newTexObj
= (*ctx
->Driver
.NewTextureObject
)(ctx
, texName
, target
);
850 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBindTexture");
854 /* and insert it into hash table */
855 _glthread_LOCK_MUTEX(ctx
->Shared
->Mutex
);
856 _mesa_HashInsert(ctx
->Shared
->TexObjects
, texName
, newTexObj
);
857 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
859 newTexObj
->Target
= target
;
862 /* XXX all RefCount accesses should be protected by a mutex. */
863 newTexObj
->RefCount
++;
865 /* do the actual binding, but first flush outstanding vertices:
867 FLUSH_VERTICES(ctx
, _NEW_TEXTURE
);
871 texUnit
->Current1D
= newTexObj
;
874 texUnit
->Current2D
= newTexObj
;
877 texUnit
->Current3D
= newTexObj
;
879 case GL_TEXTURE_CUBE_MAP_ARB
:
880 texUnit
->CurrentCubeMap
= newTexObj
;
882 case GL_TEXTURE_RECTANGLE_NV
:
883 texUnit
->CurrentRect
= newTexObj
;
886 _mesa_problem(ctx
, "bad target in BindTexture");
890 /* Pass BindTexture call to device driver */
891 if (ctx
->Driver
.BindTexture
)
892 (*ctx
->Driver
.BindTexture
)( ctx
, target
, newTexObj
);
894 /* Decrement the reference count on the old texture and check if it's
897 /* XXX all RefCount accesses should be protected by a mutex. */
898 oldTexObj
->RefCount
--;
899 ASSERT(oldTexObj
->RefCount
>= 0);
900 if (oldTexObj
->RefCount
== 0) {
901 ASSERT(oldTexObj
->Name
!= 0);
902 ASSERT(ctx
->Driver
.DeleteTexture
);
903 (*ctx
->Driver
.DeleteTexture
)( ctx
, oldTexObj
);
909 * Set texture priorities.
911 * \param n number of textures.
912 * \param texName texture names.
913 * \param priorities corresponding texture priorities.
915 * \sa glPrioritizeTextures().
917 * Looks up each texture in the hash, clamps the corresponding priority between
918 * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture.
921 _mesa_PrioritizeTextures( GLsizei n
, const GLuint
*texName
,
922 const GLclampf
*priorities
)
924 GET_CURRENT_CONTEXT(ctx
);
926 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
929 _mesa_error( ctx
, GL_INVALID_VALUE
, "glPrioritizeTextures" );
936 for (i
= 0; i
< n
; i
++) {
937 if (texName
[i
] > 0) {
938 struct gl_texture_object
*t
= (struct gl_texture_object
*)
939 _mesa_HashLookup(ctx
->Shared
->TexObjects
, texName
[i
]);
941 t
->Priority
= CLAMP( priorities
[i
], 0.0F
, 1.0F
);
942 if (ctx
->Driver
.PrioritizeTexture
)
943 ctx
->Driver
.PrioritizeTexture( ctx
, t
, t
->Priority
);
948 ctx
->NewState
|= _NEW_TEXTURE
;
952 * See if textures are loaded in texture memory.
954 * \param n number of textures to query.
955 * \param texName array with the texture names.
956 * \param residences array which will hold the residence status.
958 * \return GL_TRUE if all textures are resident and \p residences is left unchanged,
960 * \sa glAreTexturesResident().
962 * Looks up each texture in the hash and calls
963 * dd_function_table::IsTextureResident.
966 _mesa_AreTexturesResident(GLsizei n
, const GLuint
*texName
,
967 GLboolean
*residences
)
969 GET_CURRENT_CONTEXT(ctx
);
970 GLboolean allResident
= GL_TRUE
;
972 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
975 _mesa_error(ctx
, GL_INVALID_VALUE
, "glAreTexturesResident(n)");
979 if (!texName
|| !residences
)
982 for (i
= 0; i
< n
; i
++) {
983 struct gl_texture_object
*t
;
984 if (texName
[i
] == 0) {
985 _mesa_error(ctx
, GL_INVALID_VALUE
, "glAreTexturesResident");
988 t
= (struct gl_texture_object
*)
989 _mesa_HashLookup(ctx
->Shared
->TexObjects
, texName
[i
]);
991 _mesa_error(ctx
, GL_INVALID_VALUE
, "glAreTexturesResident");
994 if (!ctx
->Driver
.IsTextureResident
||
995 ctx
->Driver
.IsTextureResident(ctx
, t
)) {
996 /* The texture is resident */
998 residences
[i
] = GL_TRUE
;
1001 /* The texture is not resident */
1003 allResident
= GL_FALSE
;
1004 for (j
= 0; j
< i
; j
++)
1005 residences
[j
] = GL_TRUE
;
1007 residences
[i
] = GL_FALSE
;
1015 * See if a name corresponds to a texture.
1017 * \param texture texture name.
1019 * \return GL_TRUE if texture name corresponds to a texture, or GL_FALSE
1022 * \sa glIsTexture().
1024 * Calls _mesa_HashLookup().
1026 GLboolean GLAPIENTRY
1027 _mesa_IsTexture( GLuint texture
)
1029 struct gl_texture_object
*t
;
1030 GET_CURRENT_CONTEXT(ctx
);
1031 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
1036 t
= (struct gl_texture_object
*)
1037 _mesa_HashLookup(ctx
->Shared
->TexObjects
, texture
);
1039 /* IsTexture is true only after object has been bound once. */
1040 return t
&& t
->Target
;