texobj.c revision 7117f1b4
17117f1b4Smrg/** 27117f1b4Smrg * \file texobj.c 37117f1b4Smrg * Texture object management. 47117f1b4Smrg */ 57117f1b4Smrg 67117f1b4Smrg/* 77117f1b4Smrg * Mesa 3-D graphics library 87117f1b4Smrg * Version: 6.5 97117f1b4Smrg * 107117f1b4Smrg * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 117117f1b4Smrg * 127117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 137117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 147117f1b4Smrg * to deal in the Software without restriction, including without limitation 157117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 167117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 177117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 187117f1b4Smrg * 197117f1b4Smrg * The above copyright notice and this permission notice shall be included 207117f1b4Smrg * in all copies or substantial portions of the Software. 217117f1b4Smrg * 227117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 237117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 247117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 257117f1b4Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 267117f1b4Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 277117f1b4Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 287117f1b4Smrg */ 297117f1b4Smrg 307117f1b4Smrg 317117f1b4Smrg#include "glheader.h" 327117f1b4Smrg#include "colortab.h" 337117f1b4Smrg#include "context.h" 347117f1b4Smrg#include "enums.h" 357117f1b4Smrg#include "fbobject.h" 367117f1b4Smrg#include "hash.h" 377117f1b4Smrg#include "imports.h" 387117f1b4Smrg#include "macros.h" 397117f1b4Smrg#include "teximage.h" 407117f1b4Smrg#include "texstate.h" 417117f1b4Smrg#include "texobj.h" 427117f1b4Smrg#include "mtypes.h" 437117f1b4Smrg 447117f1b4Smrg 457117f1b4Smrg#ifdef __VMS 467117f1b4Smrg#define _mesa_sprintf sprintf 477117f1b4Smrg#endif 487117f1b4Smrg 497117f1b4Smrg/**********************************************************************/ 507117f1b4Smrg/** \name Internal functions */ 517117f1b4Smrg/*@{*/ 527117f1b4Smrg 537117f1b4Smrg 547117f1b4Smrg/** 557117f1b4Smrg * Return the gl_texture_object for a given ID. 567117f1b4Smrg */ 577117f1b4Smrgstruct gl_texture_object * 587117f1b4Smrg_mesa_lookup_texture(GLcontext *ctx, GLuint id) 597117f1b4Smrg{ 607117f1b4Smrg return (struct gl_texture_object *) 617117f1b4Smrg _mesa_HashLookup(ctx->Shared->TexObjects, id); 627117f1b4Smrg} 637117f1b4Smrg 647117f1b4Smrg 657117f1b4Smrg 667117f1b4Smrg/** 677117f1b4Smrg * Allocate and initialize a new texture object. But don't put it into the 687117f1b4Smrg * texture object hash table. 697117f1b4Smrg * 707117f1b4Smrg * Called via ctx->Driver.NewTextureObject, unless overridden by a device 717117f1b4Smrg * driver. 727117f1b4Smrg * 737117f1b4Smrg * \param shared the shared GL state structure to contain the texture object 747117f1b4Smrg * \param name integer name for the texture object 757117f1b4Smrg * \param target either GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, 767117f1b4Smrg * GL_TEXTURE_CUBE_MAP_ARB or GL_TEXTURE_RECTANGLE_NV. zero is ok for the sake 777117f1b4Smrg * of GenTextures() 787117f1b4Smrg * 797117f1b4Smrg * \return pointer to new texture object. 807117f1b4Smrg */ 817117f1b4Smrgstruct gl_texture_object * 827117f1b4Smrg_mesa_new_texture_object( GLcontext *ctx, GLuint name, GLenum target ) 837117f1b4Smrg{ 847117f1b4Smrg struct gl_texture_object *obj; 857117f1b4Smrg (void) ctx; 867117f1b4Smrg obj = MALLOC_STRUCT(gl_texture_object); 877117f1b4Smrg _mesa_initialize_texture_object(obj, name, target); 887117f1b4Smrg return obj; 897117f1b4Smrg} 907117f1b4Smrg 917117f1b4Smrg 927117f1b4Smrg/** 937117f1b4Smrg * Initialize a new texture object to default values. 947117f1b4Smrg * \param obj the texture object 957117f1b4Smrg * \param name the texture name 967117f1b4Smrg * \param target the texture target 977117f1b4Smrg */ 987117f1b4Smrgvoid 997117f1b4Smrg_mesa_initialize_texture_object( struct gl_texture_object *obj, 1007117f1b4Smrg GLuint name, GLenum target ) 1017117f1b4Smrg{ 1027117f1b4Smrg ASSERT(target == 0 || 1037117f1b4Smrg target == GL_TEXTURE_1D || 1047117f1b4Smrg target == GL_TEXTURE_2D || 1057117f1b4Smrg target == GL_TEXTURE_3D || 1067117f1b4Smrg target == GL_TEXTURE_CUBE_MAP_ARB || 1077117f1b4Smrg target == GL_TEXTURE_RECTANGLE_NV); 1087117f1b4Smrg 1097117f1b4Smrg _mesa_bzero(obj, sizeof(*obj)); 1107117f1b4Smrg /* init the non-zero fields */ 1117117f1b4Smrg _glthread_INIT_MUTEX(obj->Mutex); 1127117f1b4Smrg obj->RefCount = 1; 1137117f1b4Smrg obj->Name = name; 1147117f1b4Smrg obj->Target = target; 1157117f1b4Smrg obj->Priority = 1.0F; 1167117f1b4Smrg if (target == GL_TEXTURE_RECTANGLE_NV) { 1177117f1b4Smrg obj->WrapS = GL_CLAMP_TO_EDGE; 1187117f1b4Smrg obj->WrapT = GL_CLAMP_TO_EDGE; 1197117f1b4Smrg obj->WrapR = GL_CLAMP_TO_EDGE; 1207117f1b4Smrg obj->MinFilter = GL_LINEAR; 1217117f1b4Smrg } 1227117f1b4Smrg else { 1237117f1b4Smrg obj->WrapS = GL_REPEAT; 1247117f1b4Smrg obj->WrapT = GL_REPEAT; 1257117f1b4Smrg obj->WrapR = GL_REPEAT; 1267117f1b4Smrg obj->MinFilter = GL_NEAREST_MIPMAP_LINEAR; 1277117f1b4Smrg } 1287117f1b4Smrg obj->MagFilter = GL_LINEAR; 1297117f1b4Smrg obj->MinLod = -1000.0; 1307117f1b4Smrg obj->MaxLod = 1000.0; 1317117f1b4Smrg obj->LodBias = 0.0; 1327117f1b4Smrg obj->BaseLevel = 0; 1337117f1b4Smrg obj->MaxLevel = 1000; 1347117f1b4Smrg obj->MaxAnisotropy = 1.0; 1357117f1b4Smrg obj->CompareFlag = GL_FALSE; /* SGIX_shadow */ 1367117f1b4Smrg obj->CompareOperator = GL_TEXTURE_LEQUAL_R_SGIX; /* SGIX_shadow */ 1377117f1b4Smrg obj->CompareMode = GL_NONE; /* ARB_shadow */ 1387117f1b4Smrg obj->CompareFunc = GL_LEQUAL; /* ARB_shadow */ 1397117f1b4Smrg obj->DepthMode = GL_LUMINANCE; /* ARB_depth_texture */ 1407117f1b4Smrg obj->ShadowAmbient = 0.0F; /* ARB/SGIX_shadow_ambient */ 1417117f1b4Smrg _mesa_init_colortable(&obj->Palette); 1427117f1b4Smrg} 1437117f1b4Smrg 1447117f1b4Smrg 1457117f1b4Smrg/** 1467117f1b4Smrg * Deallocate a texture object struct. It should have already been 1477117f1b4Smrg * removed from the texture object pool. 1487117f1b4Smrg * 1497117f1b4Smrg * \param shared the shared GL state to which the object belongs. 1507117f1b4Smrg * \param texOjb the texture object to delete. 1517117f1b4Smrg */ 1527117f1b4Smrgvoid 1537117f1b4Smrg_mesa_delete_texture_object( GLcontext *ctx, struct gl_texture_object *texObj ) 1547117f1b4Smrg{ 1557117f1b4Smrg GLuint i, face; 1567117f1b4Smrg 1577117f1b4Smrg (void) ctx; 1587117f1b4Smrg 1597117f1b4Smrg /* Set Target to an invalid value. With some assertions elsewhere 1607117f1b4Smrg * we can try to detect possible use of deleted textures. 1617117f1b4Smrg */ 1627117f1b4Smrg texObj->Target = 0x99; 1637117f1b4Smrg 1647117f1b4Smrg _mesa_free_colortable_data(&texObj->Palette); 1657117f1b4Smrg 1667117f1b4Smrg /* free the texture images */ 1677117f1b4Smrg for (face = 0; face < 6; face++) { 1687117f1b4Smrg for (i = 0; i < MAX_TEXTURE_LEVELS; i++) { 1697117f1b4Smrg if (texObj->Image[face][i]) { 1707117f1b4Smrg _mesa_delete_texture_image( ctx, texObj->Image[face][i] ); 1717117f1b4Smrg } 1727117f1b4Smrg } 1737117f1b4Smrg } 1747117f1b4Smrg 1757117f1b4Smrg /* destroy the mutex -- it may have allocated memory (eg on bsd) */ 1767117f1b4Smrg _glthread_DESTROY_MUTEX(texObj->Mutex); 1777117f1b4Smrg 1787117f1b4Smrg /* free this object */ 1797117f1b4Smrg _mesa_free(texObj); 1807117f1b4Smrg} 1817117f1b4Smrg 1827117f1b4Smrg 1837117f1b4Smrg 1847117f1b4Smrg 1857117f1b4Smrg/** 1867117f1b4Smrg * Copy texture object state from one texture object to another. 1877117f1b4Smrg * Use for glPush/PopAttrib. 1887117f1b4Smrg * 1897117f1b4Smrg * \param dest destination texture object. 1907117f1b4Smrg * \param src source texture object. 1917117f1b4Smrg */ 1927117f1b4Smrgvoid 1937117f1b4Smrg_mesa_copy_texture_object( struct gl_texture_object *dest, 1947117f1b4Smrg const struct gl_texture_object *src ) 1957117f1b4Smrg{ 1967117f1b4Smrg dest->Target = src->Target; 1977117f1b4Smrg dest->Name = src->Name; 1987117f1b4Smrg dest->Priority = src->Priority; 1997117f1b4Smrg dest->BorderColor[0] = src->BorderColor[0]; 2007117f1b4Smrg dest->BorderColor[1] = src->BorderColor[1]; 2017117f1b4Smrg dest->BorderColor[2] = src->BorderColor[2]; 2027117f1b4Smrg dest->BorderColor[3] = src->BorderColor[3]; 2037117f1b4Smrg dest->WrapS = src->WrapS; 2047117f1b4Smrg dest->WrapT = src->WrapT; 2057117f1b4Smrg dest->WrapR = src->WrapR; 2067117f1b4Smrg dest->MinFilter = src->MinFilter; 2077117f1b4Smrg dest->MagFilter = src->MagFilter; 2087117f1b4Smrg dest->MinLod = src->MinLod; 2097117f1b4Smrg dest->MaxLod = src->MaxLod; 2107117f1b4Smrg dest->LodBias = src->LodBias; 2117117f1b4Smrg dest->BaseLevel = src->BaseLevel; 2127117f1b4Smrg dest->MaxLevel = src->MaxLevel; 2137117f1b4Smrg dest->MaxAnisotropy = src->MaxAnisotropy; 2147117f1b4Smrg dest->CompareFlag = src->CompareFlag; 2157117f1b4Smrg dest->CompareOperator = src->CompareOperator; 2167117f1b4Smrg dest->ShadowAmbient = src->ShadowAmbient; 2177117f1b4Smrg dest->CompareMode = src->CompareMode; 2187117f1b4Smrg dest->CompareFunc = src->CompareFunc; 2197117f1b4Smrg dest->DepthMode = src->DepthMode; 2207117f1b4Smrg dest->_MaxLevel = src->_MaxLevel; 2217117f1b4Smrg dest->_MaxLambda = src->_MaxLambda; 2227117f1b4Smrg dest->GenerateMipmap = src->GenerateMipmap; 2237117f1b4Smrg dest->Palette = src->Palette; 2247117f1b4Smrg dest->Complete = src->Complete; 2257117f1b4Smrg} 2267117f1b4Smrg 2277117f1b4Smrg 2287117f1b4Smrg/** 2297117f1b4Smrg * Check if the given texture object is valid by examining its Target field. 2307117f1b4Smrg * For debugging only. 2317117f1b4Smrg */ 2327117f1b4Smrgstatic GLboolean 2337117f1b4Smrgvalid_texture_object(const struct gl_texture_object *tex) 2347117f1b4Smrg{ 2357117f1b4Smrg switch (tex->Target) { 2367117f1b4Smrg case 0: 2377117f1b4Smrg case GL_TEXTURE_1D: 2387117f1b4Smrg case GL_TEXTURE_2D: 2397117f1b4Smrg case GL_TEXTURE_3D: 2407117f1b4Smrg case GL_TEXTURE_CUBE_MAP_ARB: 2417117f1b4Smrg case GL_TEXTURE_RECTANGLE_NV: 2427117f1b4Smrg return GL_TRUE; 2437117f1b4Smrg case 0x99: 2447117f1b4Smrg _mesa_problem(NULL, "invalid reference to a deleted texture object"); 2457117f1b4Smrg return GL_FALSE; 2467117f1b4Smrg default: 2477117f1b4Smrg _mesa_problem(NULL, "invalid texture object Target value"); 2487117f1b4Smrg return GL_FALSE; 2497117f1b4Smrg } 2507117f1b4Smrg} 2517117f1b4Smrg 2527117f1b4Smrg 2537117f1b4Smrg/** 2547117f1b4Smrg * Reference (or unreference) a texture object. 2557117f1b4Smrg * If '*ptr', decrement *ptr's refcount (and delete if it becomes zero). 2567117f1b4Smrg * If 'tex' is non-null, increment its refcount. 2577117f1b4Smrg */ 2587117f1b4Smrgvoid 2597117f1b4Smrg_mesa_reference_texobj(struct gl_texture_object **ptr, 2607117f1b4Smrg struct gl_texture_object *tex) 2617117f1b4Smrg{ 2627117f1b4Smrg assert(ptr); 2637117f1b4Smrg if (*ptr == tex) { 2647117f1b4Smrg /* no change */ 2657117f1b4Smrg return; 2667117f1b4Smrg } 2677117f1b4Smrg 2687117f1b4Smrg if (*ptr) { 2697117f1b4Smrg /* Unreference the old texture */ 2707117f1b4Smrg GLboolean deleteFlag = GL_FALSE; 2717117f1b4Smrg struct gl_texture_object *oldTex = *ptr; 2727117f1b4Smrg 2737117f1b4Smrg assert(valid_texture_object(oldTex)); 2747117f1b4Smrg 2757117f1b4Smrg _glthread_LOCK_MUTEX(oldTex->Mutex); 2767117f1b4Smrg ASSERT(oldTex->RefCount > 0); 2777117f1b4Smrg oldTex->RefCount--; 2787117f1b4Smrg 2797117f1b4Smrg deleteFlag = (oldTex->RefCount == 0); 2807117f1b4Smrg _glthread_UNLOCK_MUTEX(oldTex->Mutex); 2817117f1b4Smrg 2827117f1b4Smrg if (deleteFlag) { 2837117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 2847117f1b4Smrg if (ctx) 2857117f1b4Smrg ctx->Driver.DeleteTexture(ctx, oldTex); 2867117f1b4Smrg else 2877117f1b4Smrg _mesa_problem(NULL, "Unable to delete texture, no context"); 2887117f1b4Smrg } 2897117f1b4Smrg 2907117f1b4Smrg *ptr = NULL; 2917117f1b4Smrg } 2927117f1b4Smrg assert(!*ptr); 2937117f1b4Smrg 2947117f1b4Smrg if (tex) { 2957117f1b4Smrg /* reference new texture */ 2967117f1b4Smrg assert(valid_texture_object(tex)); 2977117f1b4Smrg _glthread_LOCK_MUTEX(tex->Mutex); 2987117f1b4Smrg if (tex->RefCount == 0) { 2997117f1b4Smrg /* this texture's being deleted (look just above) */ 3007117f1b4Smrg /* Not sure this can every really happen. Warn if it does. */ 3017117f1b4Smrg _mesa_problem(NULL, "referencing deleted texture object"); 3027117f1b4Smrg *ptr = NULL; 3037117f1b4Smrg } 3047117f1b4Smrg else { 3057117f1b4Smrg tex->RefCount++; 3067117f1b4Smrg *ptr = tex; 3077117f1b4Smrg } 3087117f1b4Smrg _glthread_UNLOCK_MUTEX(tex->Mutex); 3097117f1b4Smrg } 3107117f1b4Smrg} 3117117f1b4Smrg 3127117f1b4Smrg 3137117f1b4Smrg 3147117f1b4Smrg/** 3157117f1b4Smrg * Report why a texture object is incomplete. 3167117f1b4Smrg * 3177117f1b4Smrg * \param t texture object. 3187117f1b4Smrg * \param why string describing why it's incomplete. 3197117f1b4Smrg * 3207117f1b4Smrg * \note For debug purposes only. 3217117f1b4Smrg */ 3227117f1b4Smrg#if 0 3237117f1b4Smrgstatic void 3247117f1b4Smrgincomplete(const struct gl_texture_object *t, const char *why) 3257117f1b4Smrg{ 3267117f1b4Smrg _mesa_printf("Texture Obj %d incomplete because: %s\n", t->Name, why); 3277117f1b4Smrg} 3287117f1b4Smrg#else 3297117f1b4Smrg#define incomplete(t, why) 3307117f1b4Smrg#endif 3317117f1b4Smrg 3327117f1b4Smrg 3337117f1b4Smrg/** 3347117f1b4Smrg * Examine a texture object to determine if it is complete. 3357117f1b4Smrg * 3367117f1b4Smrg * The gl_texture_object::Complete flag will be set to GL_TRUE or GL_FALSE 3377117f1b4Smrg * accordingly. 3387117f1b4Smrg * 3397117f1b4Smrg * \param ctx GL context. 3407117f1b4Smrg * \param t texture object. 3417117f1b4Smrg * 3427117f1b4Smrg * According to the texture target, verifies that each of the mipmaps is 3437117f1b4Smrg * present and has the expected size. 3447117f1b4Smrg */ 3457117f1b4Smrgvoid 3467117f1b4Smrg_mesa_test_texobj_completeness( const GLcontext *ctx, 3477117f1b4Smrg struct gl_texture_object *t ) 3487117f1b4Smrg{ 3497117f1b4Smrg const GLint baseLevel = t->BaseLevel; 3507117f1b4Smrg GLint maxLog2 = 0, maxLevels = 0; 3517117f1b4Smrg 3527117f1b4Smrg t->Complete = GL_TRUE; /* be optimistic */ 3537117f1b4Smrg 3547117f1b4Smrg /* Always need the base level image */ 3557117f1b4Smrg if (!t->Image[0][baseLevel]) { 3567117f1b4Smrg char s[100]; 3577117f1b4Smrg _mesa_sprintf(s, "obj %p (%d) Image[baseLevel=%d] == NULL", 3587117f1b4Smrg (void *) t, t->Name, baseLevel); 3597117f1b4Smrg incomplete(t, s); 3607117f1b4Smrg t->Complete = GL_FALSE; 3617117f1b4Smrg return; 3627117f1b4Smrg } 3637117f1b4Smrg 3647117f1b4Smrg /* Check width/height/depth for zero */ 3657117f1b4Smrg if (t->Image[0][baseLevel]->Width == 0 || 3667117f1b4Smrg t->Image[0][baseLevel]->Height == 0 || 3677117f1b4Smrg t->Image[0][baseLevel]->Depth == 0) { 3687117f1b4Smrg incomplete(t, "texture width = 0"); 3697117f1b4Smrg t->Complete = GL_FALSE; 3707117f1b4Smrg return; 3717117f1b4Smrg } 3727117f1b4Smrg 3737117f1b4Smrg /* Compute _MaxLevel */ 3747117f1b4Smrg if (t->Target == GL_TEXTURE_1D) { 3757117f1b4Smrg maxLog2 = t->Image[0][baseLevel]->WidthLog2; 3767117f1b4Smrg maxLevels = ctx->Const.MaxTextureLevels; 3777117f1b4Smrg } 3787117f1b4Smrg else if (t->Target == GL_TEXTURE_2D) { 3797117f1b4Smrg maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2, 3807117f1b4Smrg t->Image[0][baseLevel]->HeightLog2); 3817117f1b4Smrg maxLevels = ctx->Const.MaxTextureLevels; 3827117f1b4Smrg } 3837117f1b4Smrg else if (t->Target == GL_TEXTURE_3D) { 3847117f1b4Smrg GLint max = MAX2(t->Image[0][baseLevel]->WidthLog2, 3857117f1b4Smrg t->Image[0][baseLevel]->HeightLog2); 3867117f1b4Smrg maxLog2 = MAX2(max, (GLint)(t->Image[0][baseLevel]->DepthLog2)); 3877117f1b4Smrg maxLevels = ctx->Const.Max3DTextureLevels; 3887117f1b4Smrg } 3897117f1b4Smrg else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) { 3907117f1b4Smrg maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2, 3917117f1b4Smrg t->Image[0][baseLevel]->HeightLog2); 3927117f1b4Smrg maxLevels = ctx->Const.MaxCubeTextureLevels; 3937117f1b4Smrg } 3947117f1b4Smrg else if (t->Target == GL_TEXTURE_RECTANGLE_NV) { 3957117f1b4Smrg maxLog2 = 0; /* not applicable */ 3967117f1b4Smrg maxLevels = 1; /* no mipmapping */ 3977117f1b4Smrg } 3987117f1b4Smrg else { 3997117f1b4Smrg _mesa_problem(ctx, "Bad t->Target in _mesa_test_texobj_completeness"); 4007117f1b4Smrg return; 4017117f1b4Smrg } 4027117f1b4Smrg 4037117f1b4Smrg ASSERT(maxLevels > 0); 4047117f1b4Smrg 4057117f1b4Smrg t->_MaxLevel = baseLevel + maxLog2; 4067117f1b4Smrg t->_MaxLevel = MIN2(t->_MaxLevel, t->MaxLevel); 4077117f1b4Smrg t->_MaxLevel = MIN2(t->_MaxLevel, maxLevels - 1); 4087117f1b4Smrg 4097117f1b4Smrg /* Compute _MaxLambda = q - b (see the 1.2 spec) used during mipmapping */ 4107117f1b4Smrg t->_MaxLambda = (GLfloat) (t->_MaxLevel - t->BaseLevel); 4117117f1b4Smrg 4127117f1b4Smrg if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) { 4137117f1b4Smrg /* make sure that all six cube map level 0 images are the same size */ 4147117f1b4Smrg const GLuint w = t->Image[0][baseLevel]->Width2; 4157117f1b4Smrg const GLuint h = t->Image[0][baseLevel]->Height2; 4167117f1b4Smrg GLuint face; 4177117f1b4Smrg for (face = 1; face < 6; face++) { 4187117f1b4Smrg if (t->Image[face][baseLevel] == NULL || 4197117f1b4Smrg t->Image[face][baseLevel]->Width2 != w || 4207117f1b4Smrg t->Image[face][baseLevel]->Height2 != h) { 4217117f1b4Smrg t->Complete = GL_FALSE; 4227117f1b4Smrg incomplete(t, "Non-quare cubemap image"); 4237117f1b4Smrg return; 4247117f1b4Smrg } 4257117f1b4Smrg } 4267117f1b4Smrg } 4277117f1b4Smrg 4287117f1b4Smrg /* extra checking for mipmaps */ 4297117f1b4Smrg if (t->MinFilter != GL_NEAREST && t->MinFilter != GL_LINEAR) { 4307117f1b4Smrg /* 4317117f1b4Smrg * Mipmapping: determine if we have a complete set of mipmaps 4327117f1b4Smrg */ 4337117f1b4Smrg GLint i; 4347117f1b4Smrg GLint minLevel = baseLevel; 4357117f1b4Smrg GLint maxLevel = t->_MaxLevel; 4367117f1b4Smrg 4377117f1b4Smrg if (minLevel > maxLevel) { 4387117f1b4Smrg t->Complete = GL_FALSE; 4397117f1b4Smrg incomplete(t, "minLevel > maxLevel"); 4407117f1b4Smrg return; 4417117f1b4Smrg } 4427117f1b4Smrg 4437117f1b4Smrg /* Test dimension-independent attributes */ 4447117f1b4Smrg for (i = minLevel; i <= maxLevel; i++) { 4457117f1b4Smrg if (t->Image[0][i]) { 4467117f1b4Smrg if (t->Image[0][i]->TexFormat != t->Image[0][baseLevel]->TexFormat) { 4477117f1b4Smrg t->Complete = GL_FALSE; 4487117f1b4Smrg incomplete(t, "Format[i] != Format[baseLevel]"); 4497117f1b4Smrg return; 4507117f1b4Smrg } 4517117f1b4Smrg if (t->Image[0][i]->Border != t->Image[0][baseLevel]->Border) { 4527117f1b4Smrg t->Complete = GL_FALSE; 4537117f1b4Smrg incomplete(t, "Border[i] != Border[baseLevel]"); 4547117f1b4Smrg return; 4557117f1b4Smrg } 4567117f1b4Smrg } 4577117f1b4Smrg } 4587117f1b4Smrg 4597117f1b4Smrg /* Test things which depend on number of texture image dimensions */ 4607117f1b4Smrg if (t->Target == GL_TEXTURE_1D) { 4617117f1b4Smrg /* Test 1-D mipmaps */ 4627117f1b4Smrg GLuint width = t->Image[0][baseLevel]->Width2; 4637117f1b4Smrg for (i = baseLevel + 1; i < maxLevels; i++) { 4647117f1b4Smrg if (width > 1) { 4657117f1b4Smrg width /= 2; 4667117f1b4Smrg } 4677117f1b4Smrg if (i >= minLevel && i <= maxLevel) { 4687117f1b4Smrg if (!t->Image[0][i]) { 4697117f1b4Smrg t->Complete = GL_FALSE; 4707117f1b4Smrg incomplete(t, "1D Image[0][i] == NULL"); 4717117f1b4Smrg return; 4727117f1b4Smrg } 4737117f1b4Smrg if (t->Image[0][i]->Width2 != width ) { 4747117f1b4Smrg t->Complete = GL_FALSE; 4757117f1b4Smrg incomplete(t, "1D Image[0][i] bad width"); 4767117f1b4Smrg return; 4777117f1b4Smrg } 4787117f1b4Smrg } 4797117f1b4Smrg if (width == 1) { 4807117f1b4Smrg return; /* found smallest needed mipmap, all done! */ 4817117f1b4Smrg } 4827117f1b4Smrg } 4837117f1b4Smrg } 4847117f1b4Smrg else if (t->Target == GL_TEXTURE_2D) { 4857117f1b4Smrg /* Test 2-D mipmaps */ 4867117f1b4Smrg GLuint width = t->Image[0][baseLevel]->Width2; 4877117f1b4Smrg GLuint height = t->Image[0][baseLevel]->Height2; 4887117f1b4Smrg for (i = baseLevel + 1; i < maxLevels; i++) { 4897117f1b4Smrg if (width > 1) { 4907117f1b4Smrg width /= 2; 4917117f1b4Smrg } 4927117f1b4Smrg if (height > 1) { 4937117f1b4Smrg height /= 2; 4947117f1b4Smrg } 4957117f1b4Smrg if (i >= minLevel && i <= maxLevel) { 4967117f1b4Smrg if (!t->Image[0][i]) { 4977117f1b4Smrg t->Complete = GL_FALSE; 4987117f1b4Smrg incomplete(t, "2D Image[0][i] == NULL"); 4997117f1b4Smrg return; 5007117f1b4Smrg } 5017117f1b4Smrg if (t->Image[0][i]->Width2 != width) { 5027117f1b4Smrg t->Complete = GL_FALSE; 5037117f1b4Smrg incomplete(t, "2D Image[0][i] bad width"); 5047117f1b4Smrg return; 5057117f1b4Smrg } 5067117f1b4Smrg if (t->Image[0][i]->Height2 != height) { 5077117f1b4Smrg t->Complete = GL_FALSE; 5087117f1b4Smrg incomplete(t, "2D Image[0][i] bad height"); 5097117f1b4Smrg return; 5107117f1b4Smrg } 5117117f1b4Smrg if (width==1 && height==1) { 5127117f1b4Smrg return; /* found smallest needed mipmap, all done! */ 5137117f1b4Smrg } 5147117f1b4Smrg } 5157117f1b4Smrg } 5167117f1b4Smrg } 5177117f1b4Smrg else if (t->Target == GL_TEXTURE_3D) { 5187117f1b4Smrg /* Test 3-D mipmaps */ 5197117f1b4Smrg GLuint width = t->Image[0][baseLevel]->Width2; 5207117f1b4Smrg GLuint height = t->Image[0][baseLevel]->Height2; 5217117f1b4Smrg GLuint depth = t->Image[0][baseLevel]->Depth2; 5227117f1b4Smrg for (i = baseLevel + 1; i < maxLevels; i++) { 5237117f1b4Smrg if (width > 1) { 5247117f1b4Smrg width /= 2; 5257117f1b4Smrg } 5267117f1b4Smrg if (height > 1) { 5277117f1b4Smrg height /= 2; 5287117f1b4Smrg } 5297117f1b4Smrg if (depth > 1) { 5307117f1b4Smrg depth /= 2; 5317117f1b4Smrg } 5327117f1b4Smrg if (i >= minLevel && i <= maxLevel) { 5337117f1b4Smrg if (!t->Image[0][i]) { 5347117f1b4Smrg incomplete(t, "3D Image[0][i] == NULL"); 5357117f1b4Smrg t->Complete = GL_FALSE; 5367117f1b4Smrg return; 5377117f1b4Smrg } 5387117f1b4Smrg if (t->Image[0][i]->_BaseFormat == GL_DEPTH_COMPONENT) { 5397117f1b4Smrg t->Complete = GL_FALSE; 5407117f1b4Smrg incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex"); 5417117f1b4Smrg return; 5427117f1b4Smrg } 5437117f1b4Smrg if (t->Image[0][i]->Width2 != width) { 5447117f1b4Smrg t->Complete = GL_FALSE; 5457117f1b4Smrg incomplete(t, "3D Image[0][i] bad width"); 5467117f1b4Smrg return; 5477117f1b4Smrg } 5487117f1b4Smrg if (t->Image[0][i]->Height2 != height) { 5497117f1b4Smrg t->Complete = GL_FALSE; 5507117f1b4Smrg incomplete(t, "3D Image[0][i] bad height"); 5517117f1b4Smrg return; 5527117f1b4Smrg } 5537117f1b4Smrg if (t->Image[0][i]->Depth2 != depth) { 5547117f1b4Smrg t->Complete = GL_FALSE; 5557117f1b4Smrg incomplete(t, "3D Image[0][i] bad depth"); 5567117f1b4Smrg return; 5577117f1b4Smrg } 5587117f1b4Smrg } 5597117f1b4Smrg if (width == 1 && height == 1 && depth == 1) { 5607117f1b4Smrg return; /* found smallest needed mipmap, all done! */ 5617117f1b4Smrg } 5627117f1b4Smrg } 5637117f1b4Smrg } 5647117f1b4Smrg else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) { 5657117f1b4Smrg /* make sure 6 cube faces are consistant */ 5667117f1b4Smrg GLuint width = t->Image[0][baseLevel]->Width2; 5677117f1b4Smrg GLuint height = t->Image[0][baseLevel]->Height2; 5687117f1b4Smrg for (i = baseLevel + 1; i < maxLevels; i++) { 5697117f1b4Smrg if (width > 1) { 5707117f1b4Smrg width /= 2; 5717117f1b4Smrg } 5727117f1b4Smrg if (height > 1) { 5737117f1b4Smrg height /= 2; 5747117f1b4Smrg } 5757117f1b4Smrg if (i >= minLevel && i <= maxLevel) { 5767117f1b4Smrg GLuint face; 5777117f1b4Smrg for (face = 0; face < 6; face++) { 5787117f1b4Smrg /* check that we have images defined */ 5797117f1b4Smrg if (!t->Image[face][i]) { 5807117f1b4Smrg t->Complete = GL_FALSE; 5817117f1b4Smrg incomplete(t, "CubeMap Image[n][i] == NULL"); 5827117f1b4Smrg return; 5837117f1b4Smrg } 5847117f1b4Smrg /* Don't support GL_DEPTH_COMPONENT for cube maps */ 5857117f1b4Smrg if (t->Image[face][i]->_BaseFormat == GL_DEPTH_COMPONENT) { 5867117f1b4Smrg t->Complete = GL_FALSE; 5877117f1b4Smrg incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex"); 5887117f1b4Smrg return; 5897117f1b4Smrg } 5907117f1b4Smrg /* check that all six images have same size */ 5917117f1b4Smrg if (t->Image[face][i]->Width2!=width || 5927117f1b4Smrg t->Image[face][i]->Height2!=height) { 5937117f1b4Smrg t->Complete = GL_FALSE; 5947117f1b4Smrg incomplete(t, "CubeMap Image[n][i] bad size"); 5957117f1b4Smrg return; 5967117f1b4Smrg } 5977117f1b4Smrg } 5987117f1b4Smrg } 5997117f1b4Smrg if (width == 1 && height == 1) { 6007117f1b4Smrg return; /* found smallest needed mipmap, all done! */ 6017117f1b4Smrg } 6027117f1b4Smrg } 6037117f1b4Smrg } 6047117f1b4Smrg else if (t->Target == GL_TEXTURE_RECTANGLE_NV) { 6057117f1b4Smrg /* XXX special checking? */ 6067117f1b4Smrg } 6077117f1b4Smrg else { 6087117f1b4Smrg /* Target = ??? */ 6097117f1b4Smrg _mesa_problem(ctx, "Bug in gl_test_texture_object_completeness\n"); 6107117f1b4Smrg } 6117117f1b4Smrg } 6127117f1b4Smrg} 6137117f1b4Smrg 6147117f1b4Smrg/*@}*/ 6157117f1b4Smrg 6167117f1b4Smrg 6177117f1b4Smrg/***********************************************************************/ 6187117f1b4Smrg/** \name API functions */ 6197117f1b4Smrg/*@{*/ 6207117f1b4Smrg 6217117f1b4Smrg/** 6227117f1b4Smrg * Texture name generation lock. 6237117f1b4Smrg * 6247117f1b4Smrg * Used by _mesa_GenTextures() to guarantee that the generation and allocation 6257117f1b4Smrg * of texture IDs is atomic. 6267117f1b4Smrg */ 6277117f1b4Smrg_glthread_DECLARE_STATIC_MUTEX(GenTexturesLock); 6287117f1b4Smrg 6297117f1b4Smrg/** 6307117f1b4Smrg * Generate texture names. 6317117f1b4Smrg * 6327117f1b4Smrg * \param n number of texture names to be generated. 6337117f1b4Smrg * \param textures an array in which will hold the generated texture names. 6347117f1b4Smrg * 6357117f1b4Smrg * \sa glGenTextures(). 6367117f1b4Smrg * 6377117f1b4Smrg * While holding the GenTexturesLock lock, calls _mesa_HashFindFreeKeyBlock() 6387117f1b4Smrg * to find a block of free texture IDs which are stored in \p textures. 6397117f1b4Smrg * Corresponding empty texture objects are also generated. 6407117f1b4Smrg */ 6417117f1b4Smrgvoid GLAPIENTRY 6427117f1b4Smrg_mesa_GenTextures( GLsizei n, GLuint *textures ) 6437117f1b4Smrg{ 6447117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 6457117f1b4Smrg GLuint first; 6467117f1b4Smrg GLint i; 6477117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 6487117f1b4Smrg 6497117f1b4Smrg if (n < 0) { 6507117f1b4Smrg _mesa_error( ctx, GL_INVALID_VALUE, "glGenTextures" ); 6517117f1b4Smrg return; 6527117f1b4Smrg } 6537117f1b4Smrg 6547117f1b4Smrg if (!textures) 6557117f1b4Smrg return; 6567117f1b4Smrg 6577117f1b4Smrg /* 6587117f1b4Smrg * This must be atomic (generation and allocation of texture IDs) 6597117f1b4Smrg */ 6607117f1b4Smrg _glthread_LOCK_MUTEX(GenTexturesLock); 6617117f1b4Smrg 6627117f1b4Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Shared->TexObjects, n); 6637117f1b4Smrg 6647117f1b4Smrg /* Allocate new, empty texture objects */ 6657117f1b4Smrg for (i = 0; i < n; i++) { 6667117f1b4Smrg struct gl_texture_object *texObj; 6677117f1b4Smrg GLuint name = first + i; 6687117f1b4Smrg GLenum target = 0; 6697117f1b4Smrg texObj = (*ctx->Driver.NewTextureObject)( ctx, name, target); 6707117f1b4Smrg if (!texObj) { 6717117f1b4Smrg _glthread_UNLOCK_MUTEX(GenTexturesLock); 6727117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures"); 6737117f1b4Smrg return; 6747117f1b4Smrg } 6757117f1b4Smrg 6767117f1b4Smrg /* insert into hash table */ 6777117f1b4Smrg _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 6787117f1b4Smrg _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj); 6797117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 6807117f1b4Smrg 6817117f1b4Smrg textures[i] = name; 6827117f1b4Smrg } 6837117f1b4Smrg 6847117f1b4Smrg _glthread_UNLOCK_MUTEX(GenTexturesLock); 6857117f1b4Smrg} 6867117f1b4Smrg 6877117f1b4Smrg 6887117f1b4Smrg/** 6897117f1b4Smrg * Check if the given texture object is bound to the current draw or 6907117f1b4Smrg * read framebuffer. If so, Unbind it. 6917117f1b4Smrg */ 6927117f1b4Smrgstatic void 6937117f1b4Smrgunbind_texobj_from_fbo(GLcontext *ctx, struct gl_texture_object *texObj) 6947117f1b4Smrg{ 6957117f1b4Smrg const GLuint n = (ctx->DrawBuffer == ctx->ReadBuffer) ? 1 : 2; 6967117f1b4Smrg GLuint i; 6977117f1b4Smrg 6987117f1b4Smrg for (i = 0; i < n; i++) { 6997117f1b4Smrg struct gl_framebuffer *fb = (i == 0) ? ctx->DrawBuffer : ctx->ReadBuffer; 7007117f1b4Smrg if (fb->Name) { 7017117f1b4Smrg GLuint j; 7027117f1b4Smrg for (j = 0; j < BUFFER_COUNT; j++) { 7037117f1b4Smrg if (fb->Attachment[j].Type == GL_TEXTURE && 7047117f1b4Smrg fb->Attachment[j].Texture == texObj) { 7057117f1b4Smrg _mesa_remove_attachment(ctx, fb->Attachment + j); 7067117f1b4Smrg } 7077117f1b4Smrg } 7087117f1b4Smrg } 7097117f1b4Smrg } 7107117f1b4Smrg} 7117117f1b4Smrg 7127117f1b4Smrg 7137117f1b4Smrg/** 7147117f1b4Smrg * Check if the given texture object is bound to any texture image units and 7157117f1b4Smrg * unbind it if so (revert to default textures). 7167117f1b4Smrg */ 7177117f1b4Smrgstatic void 7187117f1b4Smrgunbind_texobj_from_texunits(GLcontext *ctx, struct gl_texture_object *texObj) 7197117f1b4Smrg{ 7207117f1b4Smrg GLuint u; 7217117f1b4Smrg 7227117f1b4Smrg for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) { 7237117f1b4Smrg struct gl_texture_unit *unit = &ctx->Texture.Unit[u]; 7247117f1b4Smrg if (texObj == unit->Current1D) { 7257117f1b4Smrg _mesa_reference_texobj(&unit->Current1D, ctx->Shared->Default1D); 7267117f1b4Smrg } 7277117f1b4Smrg else if (texObj == unit->Current2D) { 7287117f1b4Smrg _mesa_reference_texobj(&unit->Current2D, ctx->Shared->Default2D); 7297117f1b4Smrg } 7307117f1b4Smrg else if (texObj == unit->Current3D) { 7317117f1b4Smrg _mesa_reference_texobj(&unit->Current3D, ctx->Shared->Default3D); 7327117f1b4Smrg } 7337117f1b4Smrg else if (texObj == unit->CurrentCubeMap) { 7347117f1b4Smrg _mesa_reference_texobj(&unit->CurrentCubeMap, ctx->Shared->DefaultCubeMap); 7357117f1b4Smrg } 7367117f1b4Smrg else if (texObj == unit->CurrentRect) { 7377117f1b4Smrg _mesa_reference_texobj(&unit->CurrentRect, ctx->Shared->DefaultRect); 7387117f1b4Smrg } 7397117f1b4Smrg } 7407117f1b4Smrg} 7417117f1b4Smrg 7427117f1b4Smrg 7437117f1b4Smrg/** 7447117f1b4Smrg * Delete named textures. 7457117f1b4Smrg * 7467117f1b4Smrg * \param n number of textures to be deleted. 7477117f1b4Smrg * \param textures array of texture IDs to be deleted. 7487117f1b4Smrg * 7497117f1b4Smrg * \sa glDeleteTextures(). 7507117f1b4Smrg * 7517117f1b4Smrg * If we're about to delete a texture that's currently bound to any 7527117f1b4Smrg * texture unit, unbind the texture first. Decrement the reference 7537117f1b4Smrg * count on the texture object and delete it if it's zero. 7547117f1b4Smrg * Recall that texture objects can be shared among several rendering 7557117f1b4Smrg * contexts. 7567117f1b4Smrg */ 7577117f1b4Smrgvoid GLAPIENTRY 7587117f1b4Smrg_mesa_DeleteTextures( GLsizei n, const GLuint *textures) 7597117f1b4Smrg{ 7607117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 7617117f1b4Smrg GLint i; 7627117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */ 7637117f1b4Smrg 7647117f1b4Smrg if (!textures) 7657117f1b4Smrg return; 7667117f1b4Smrg 7677117f1b4Smrg for (i = 0; i < n; i++) { 7687117f1b4Smrg if (textures[i] > 0) { 7697117f1b4Smrg struct gl_texture_object *delObj 7707117f1b4Smrg = _mesa_lookup_texture(ctx, textures[i]); 7717117f1b4Smrg 7727117f1b4Smrg if (delObj) { 7737117f1b4Smrg _mesa_lock_texture(ctx, delObj); 7747117f1b4Smrg 7757117f1b4Smrg /* Check if texture is bound to any framebuffer objects. 7767117f1b4Smrg * If so, unbind. 7777117f1b4Smrg * See section 4.4.2.3 of GL_EXT_framebuffer_object. 7787117f1b4Smrg */ 7797117f1b4Smrg unbind_texobj_from_fbo(ctx, delObj); 7807117f1b4Smrg 7817117f1b4Smrg /* Check if this texture is currently bound to any texture units. 7827117f1b4Smrg * If so, unbind it. 7837117f1b4Smrg */ 7847117f1b4Smrg unbind_texobj_from_texunits(ctx, delObj); 7857117f1b4Smrg 7867117f1b4Smrg _mesa_unlock_texture(ctx, delObj); 7877117f1b4Smrg 7887117f1b4Smrg ctx->NewState |= _NEW_TEXTURE; 7897117f1b4Smrg 7907117f1b4Smrg /* The texture _name_ is now free for re-use. 7917117f1b4Smrg * Remove it from the hash table now. 7927117f1b4Smrg */ 7937117f1b4Smrg _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 7947117f1b4Smrg _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name); 7957117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 7967117f1b4Smrg 7977117f1b4Smrg /* Unreference the texobj. If refcount hits zero, the texture 7987117f1b4Smrg * will be deleted. 7997117f1b4Smrg */ 8007117f1b4Smrg _mesa_reference_texobj(&delObj, NULL); 8017117f1b4Smrg } 8027117f1b4Smrg } 8037117f1b4Smrg } 8047117f1b4Smrg} 8057117f1b4Smrg 8067117f1b4Smrg 8077117f1b4Smrg/** 8087117f1b4Smrg * Bind a named texture to a texturing target. 8097117f1b4Smrg * 8107117f1b4Smrg * \param target texture target. 8117117f1b4Smrg * \param texName texture name. 8127117f1b4Smrg * 8137117f1b4Smrg * \sa glBindTexture(). 8147117f1b4Smrg * 8157117f1b4Smrg * Determines the old texture object bound and returns immediately if rebinding 8167117f1b4Smrg * the same texture. Get the current texture which is either a default texture 8177117f1b4Smrg * if name is null, a named texture from the hash, or a new texture if the 8187117f1b4Smrg * given texture name is new. Increments its reference count, binds it, and 8197117f1b4Smrg * calls dd_function_table::BindTexture. Decrements the old texture reference 8207117f1b4Smrg * count and deletes it if it reaches zero. 8217117f1b4Smrg */ 8227117f1b4Smrgvoid GLAPIENTRY 8237117f1b4Smrg_mesa_BindTexture( GLenum target, GLuint texName ) 8247117f1b4Smrg{ 8257117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 8267117f1b4Smrg const GLuint unit = ctx->Texture.CurrentUnit; 8277117f1b4Smrg struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; 8287117f1b4Smrg struct gl_texture_object *newTexObj = NULL; 8297117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 8307117f1b4Smrg 8317117f1b4Smrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 8327117f1b4Smrg _mesa_debug(ctx, "glBindTexture %s %d\n", 8337117f1b4Smrg _mesa_lookup_enum_by_nr(target), (GLint) texName); 8347117f1b4Smrg 8357117f1b4Smrg /* 8367117f1b4Smrg * Get pointer to new texture object (newTexObj) 8377117f1b4Smrg */ 8387117f1b4Smrg if (texName == 0) { 8397117f1b4Smrg /* newTexObj = a default texture object */ 8407117f1b4Smrg switch (target) { 8417117f1b4Smrg case GL_TEXTURE_1D: 8427117f1b4Smrg newTexObj = ctx->Shared->Default1D; 8437117f1b4Smrg break; 8447117f1b4Smrg case GL_TEXTURE_2D: 8457117f1b4Smrg newTexObj = ctx->Shared->Default2D; 8467117f1b4Smrg break; 8477117f1b4Smrg case GL_TEXTURE_3D: 8487117f1b4Smrg newTexObj = ctx->Shared->Default3D; 8497117f1b4Smrg break; 8507117f1b4Smrg case GL_TEXTURE_CUBE_MAP_ARB: 8517117f1b4Smrg newTexObj = ctx->Shared->DefaultCubeMap; 8527117f1b4Smrg break; 8537117f1b4Smrg case GL_TEXTURE_RECTANGLE_NV: 8547117f1b4Smrg newTexObj = ctx->Shared->DefaultRect; 8557117f1b4Smrg break; 8567117f1b4Smrg default: 8577117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)"); 8587117f1b4Smrg return; 8597117f1b4Smrg } 8607117f1b4Smrg } 8617117f1b4Smrg else { 8627117f1b4Smrg /* non-default texture object */ 8637117f1b4Smrg newTexObj = _mesa_lookup_texture(ctx, texName); 8647117f1b4Smrg if (newTexObj) { 8657117f1b4Smrg /* error checking */ 8667117f1b4Smrg if (newTexObj->Target != 0 && newTexObj->Target != target) { 8677117f1b4Smrg /* the named texture object's dimensions don't match the target */ 8687117f1b4Smrg _mesa_error( ctx, GL_INVALID_OPERATION, 8697117f1b4Smrg "glBindTexture(wrong dimensionality)" ); 8707117f1b4Smrg return; 8717117f1b4Smrg } 8727117f1b4Smrg if (newTexObj->Target == 0 && target == GL_TEXTURE_RECTANGLE_NV) { 8737117f1b4Smrg /* have to init wrap and filter state here - kind of klunky */ 8747117f1b4Smrg newTexObj->WrapS = GL_CLAMP_TO_EDGE; 8757117f1b4Smrg newTexObj->WrapT = GL_CLAMP_TO_EDGE; 8767117f1b4Smrg newTexObj->WrapR = GL_CLAMP_TO_EDGE; 8777117f1b4Smrg newTexObj->MinFilter = GL_LINEAR; 8787117f1b4Smrg if (ctx->Driver.TexParameter) { 8797117f1b4Smrg static const GLfloat fparam_wrap[1] = {(GLfloat) GL_CLAMP_TO_EDGE}; 8807117f1b4Smrg static const GLfloat fparam_filter[1] = {(GLfloat) GL_LINEAR}; 8817117f1b4Smrg (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_WRAP_S, fparam_wrap ); 8827117f1b4Smrg (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_WRAP_T, fparam_wrap ); 8837117f1b4Smrg (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_WRAP_R, fparam_wrap ); 8847117f1b4Smrg (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_MIN_FILTER, fparam_filter ); 8857117f1b4Smrg } 8867117f1b4Smrg } 8877117f1b4Smrg } 8887117f1b4Smrg else { 8897117f1b4Smrg /* if this is a new texture id, allocate a texture object now */ 8907117f1b4Smrg newTexObj = (*ctx->Driver.NewTextureObject)(ctx, texName, target); 8917117f1b4Smrg if (!newTexObj) { 8927117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture"); 8937117f1b4Smrg return; 8947117f1b4Smrg } 8957117f1b4Smrg 8967117f1b4Smrg /* and insert it into hash table */ 8977117f1b4Smrg _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 8987117f1b4Smrg _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj); 8997117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 9007117f1b4Smrg } 9017117f1b4Smrg newTexObj->Target = target; 9027117f1b4Smrg } 9037117f1b4Smrg 9047117f1b4Smrg assert(valid_texture_object(newTexObj)); 9057117f1b4Smrg 9067117f1b4Smrg /* flush before changing binding */ 9077117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_TEXTURE); 9087117f1b4Smrg 9097117f1b4Smrg /* Do the actual binding. The refcount on the previously bound 9107117f1b4Smrg * texture object will be decremented. It'll be deleted if the 9117117f1b4Smrg * count hits zero. 9127117f1b4Smrg */ 9137117f1b4Smrg switch (target) { 9147117f1b4Smrg case GL_TEXTURE_1D: 9157117f1b4Smrg _mesa_reference_texobj(&texUnit->Current1D, newTexObj); 9167117f1b4Smrg break; 9177117f1b4Smrg case GL_TEXTURE_2D: 9187117f1b4Smrg _mesa_reference_texobj(&texUnit->Current2D, newTexObj); 9197117f1b4Smrg break; 9207117f1b4Smrg case GL_TEXTURE_3D: 9217117f1b4Smrg _mesa_reference_texobj(&texUnit->Current3D, newTexObj); 9227117f1b4Smrg break; 9237117f1b4Smrg case GL_TEXTURE_CUBE_MAP_ARB: 9247117f1b4Smrg _mesa_reference_texobj(&texUnit->CurrentCubeMap, newTexObj); 9257117f1b4Smrg break; 9267117f1b4Smrg case GL_TEXTURE_RECTANGLE_NV: 9277117f1b4Smrg _mesa_reference_texobj(&texUnit->CurrentRect, newTexObj); 9287117f1b4Smrg break; 9297117f1b4Smrg default: 9307117f1b4Smrg /* Bad target should be caught above */ 9317117f1b4Smrg _mesa_problem(ctx, "bad target in BindTexture"); 9327117f1b4Smrg return; 9337117f1b4Smrg } 9347117f1b4Smrg 9357117f1b4Smrg /* Pass BindTexture call to device driver */ 9367117f1b4Smrg if (ctx->Driver.BindTexture) 9377117f1b4Smrg (*ctx->Driver.BindTexture)( ctx, target, newTexObj ); 9387117f1b4Smrg} 9397117f1b4Smrg 9407117f1b4Smrg 9417117f1b4Smrg/** 9427117f1b4Smrg * Set texture priorities. 9437117f1b4Smrg * 9447117f1b4Smrg * \param n number of textures. 9457117f1b4Smrg * \param texName texture names. 9467117f1b4Smrg * \param priorities corresponding texture priorities. 9477117f1b4Smrg * 9487117f1b4Smrg * \sa glPrioritizeTextures(). 9497117f1b4Smrg * 9507117f1b4Smrg * Looks up each texture in the hash, clamps the corresponding priority between 9517117f1b4Smrg * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture. 9527117f1b4Smrg */ 9537117f1b4Smrgvoid GLAPIENTRY 9547117f1b4Smrg_mesa_PrioritizeTextures( GLsizei n, const GLuint *texName, 9557117f1b4Smrg const GLclampf *priorities ) 9567117f1b4Smrg{ 9577117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 9587117f1b4Smrg GLint i; 9597117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 9607117f1b4Smrg 9617117f1b4Smrg if (n < 0) { 9627117f1b4Smrg _mesa_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" ); 9637117f1b4Smrg return; 9647117f1b4Smrg } 9657117f1b4Smrg 9667117f1b4Smrg if (!priorities) 9677117f1b4Smrg return; 9687117f1b4Smrg 9697117f1b4Smrg for (i = 0; i < n; i++) { 9707117f1b4Smrg if (texName[i] > 0) { 9717117f1b4Smrg struct gl_texture_object *t = _mesa_lookup_texture(ctx, texName[i]); 9727117f1b4Smrg if (t) { 9737117f1b4Smrg t->Priority = CLAMP( priorities[i], 0.0F, 1.0F ); 9747117f1b4Smrg if (ctx->Driver.PrioritizeTexture) 9757117f1b4Smrg ctx->Driver.PrioritizeTexture( ctx, t, t->Priority ); 9767117f1b4Smrg } 9777117f1b4Smrg } 9787117f1b4Smrg } 9797117f1b4Smrg 9807117f1b4Smrg ctx->NewState |= _NEW_TEXTURE; 9817117f1b4Smrg} 9827117f1b4Smrg 9837117f1b4Smrg/** 9847117f1b4Smrg * See if textures are loaded in texture memory. 9857117f1b4Smrg * 9867117f1b4Smrg * \param n number of textures to query. 9877117f1b4Smrg * \param texName array with the texture names. 9887117f1b4Smrg * \param residences array which will hold the residence status. 9897117f1b4Smrg * 9907117f1b4Smrg * \return GL_TRUE if all textures are resident and \p residences is left unchanged, 9917117f1b4Smrg * 9927117f1b4Smrg * \sa glAreTexturesResident(). 9937117f1b4Smrg * 9947117f1b4Smrg * Looks up each texture in the hash and calls 9957117f1b4Smrg * dd_function_table::IsTextureResident. 9967117f1b4Smrg */ 9977117f1b4SmrgGLboolean GLAPIENTRY 9987117f1b4Smrg_mesa_AreTexturesResident(GLsizei n, const GLuint *texName, 9997117f1b4Smrg GLboolean *residences) 10007117f1b4Smrg{ 10017117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 10027117f1b4Smrg GLboolean allResident = GL_TRUE; 10037117f1b4Smrg GLint i, j; 10047117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 10057117f1b4Smrg 10067117f1b4Smrg if (n < 0) { 10077117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)"); 10087117f1b4Smrg return GL_FALSE; 10097117f1b4Smrg } 10107117f1b4Smrg 10117117f1b4Smrg if (!texName || !residences) 10127117f1b4Smrg return GL_FALSE; 10137117f1b4Smrg 10147117f1b4Smrg for (i = 0; i < n; i++) { 10157117f1b4Smrg struct gl_texture_object *t; 10167117f1b4Smrg if (texName[i] == 0) { 10177117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident"); 10187117f1b4Smrg return GL_FALSE; 10197117f1b4Smrg } 10207117f1b4Smrg t = _mesa_lookup_texture(ctx, texName[i]); 10217117f1b4Smrg if (!t) { 10227117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident"); 10237117f1b4Smrg return GL_FALSE; 10247117f1b4Smrg } 10257117f1b4Smrg if (!ctx->Driver.IsTextureResident || 10267117f1b4Smrg ctx->Driver.IsTextureResident(ctx, t)) { 10277117f1b4Smrg /* The texture is resident */ 10287117f1b4Smrg if (!allResident) 10297117f1b4Smrg residences[i] = GL_TRUE; 10307117f1b4Smrg } 10317117f1b4Smrg else { 10327117f1b4Smrg /* The texture is not resident */ 10337117f1b4Smrg if (allResident) { 10347117f1b4Smrg allResident = GL_FALSE; 10357117f1b4Smrg for (j = 0; j < i; j++) 10367117f1b4Smrg residences[j] = GL_TRUE; 10377117f1b4Smrg } 10387117f1b4Smrg residences[i] = GL_FALSE; 10397117f1b4Smrg } 10407117f1b4Smrg } 10417117f1b4Smrg 10427117f1b4Smrg return allResident; 10437117f1b4Smrg} 10447117f1b4Smrg 10457117f1b4Smrg/** 10467117f1b4Smrg * See if a name corresponds to a texture. 10477117f1b4Smrg * 10487117f1b4Smrg * \param texture texture name. 10497117f1b4Smrg * 10507117f1b4Smrg * \return GL_TRUE if texture name corresponds to a texture, or GL_FALSE 10517117f1b4Smrg * otherwise. 10527117f1b4Smrg * 10537117f1b4Smrg * \sa glIsTexture(). 10547117f1b4Smrg * 10557117f1b4Smrg * Calls _mesa_HashLookup(). 10567117f1b4Smrg */ 10577117f1b4SmrgGLboolean GLAPIENTRY 10587117f1b4Smrg_mesa_IsTexture( GLuint texture ) 10597117f1b4Smrg{ 10607117f1b4Smrg struct gl_texture_object *t; 10617117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 10627117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 10637117f1b4Smrg 10647117f1b4Smrg if (!texture) 10657117f1b4Smrg return GL_FALSE; 10667117f1b4Smrg 10677117f1b4Smrg t = _mesa_lookup_texture(ctx, texture); 10687117f1b4Smrg 10697117f1b4Smrg /* IsTexture is true only after object has been bound once. */ 10707117f1b4Smrg return t && t->Target; 10717117f1b4Smrg} 10727117f1b4Smrg 10737117f1b4Smrg/* Simplest implementation of texture locking: Grab the a new mutex in 10747117f1b4Smrg * the shared context. Examine the shared context state timestamp and 10757117f1b4Smrg * if there has been a change, set the appropriate bits in 10767117f1b4Smrg * ctx->NewState. 10777117f1b4Smrg * 10787117f1b4Smrg * See also _mesa_lock/unlock_texture in texobj.h 10797117f1b4Smrg */ 10807117f1b4Smrgvoid _mesa_lock_context_textures( GLcontext *ctx ) 10817117f1b4Smrg{ 10827117f1b4Smrg _glthread_LOCK_MUTEX(ctx->Shared->TexMutex); 10837117f1b4Smrg 10847117f1b4Smrg if (ctx->Shared->TextureStateStamp != ctx->TextureStateTimestamp) { 10857117f1b4Smrg ctx->NewState |= _NEW_TEXTURE; 10867117f1b4Smrg ctx->TextureStateTimestamp = ctx->Shared->TextureStateStamp; 10877117f1b4Smrg } 10887117f1b4Smrg} 10897117f1b4Smrg 10907117f1b4Smrg 10917117f1b4Smrgvoid _mesa_unlock_context_textures( GLcontext *ctx ) 10927117f1b4Smrg{ 10937117f1b4Smrg assert(ctx->Shared->TextureStateStamp == ctx->TextureStateTimestamp); 10947117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->TexMutex); 10957117f1b4Smrg} 10967117f1b4Smrg 10977117f1b4Smrg/*@}*/ 10987117f1b4Smrg 10997117f1b4Smrg 1100