texobj.c revision c1f859d4
17117f1b4Smrg/** 27117f1b4Smrg * \file texobj.c 37117f1b4Smrg * Texture object management. 47117f1b4Smrg */ 57117f1b4Smrg 67117f1b4Smrg/* 77117f1b4Smrg * Mesa 3-D graphics library 8c1f859d4Smrg * Version: 7.1 97117f1b4Smrg * 10c1f859d4Smrg * Copyright (C) 1999-2007 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" 32c1f859d4Smrg#if FEATURE_colortable 337117f1b4Smrg#include "colortab.h" 34c1f859d4Smrg#endif 357117f1b4Smrg#include "context.h" 367117f1b4Smrg#include "enums.h" 377117f1b4Smrg#include "fbobject.h" 387117f1b4Smrg#include "hash.h" 397117f1b4Smrg#include "imports.h" 407117f1b4Smrg#include "macros.h" 417117f1b4Smrg#include "teximage.h" 427117f1b4Smrg#include "texstate.h" 437117f1b4Smrg#include "texobj.h" 447117f1b4Smrg#include "mtypes.h" 457117f1b4Smrg 467117f1b4Smrg 477117f1b4Smrg/**********************************************************************/ 487117f1b4Smrg/** \name Internal functions */ 497117f1b4Smrg/*@{*/ 507117f1b4Smrg 517117f1b4Smrg 527117f1b4Smrg/** 537117f1b4Smrg * Return the gl_texture_object for a given ID. 547117f1b4Smrg */ 557117f1b4Smrgstruct gl_texture_object * 567117f1b4Smrg_mesa_lookup_texture(GLcontext *ctx, GLuint id) 577117f1b4Smrg{ 587117f1b4Smrg return (struct gl_texture_object *) 597117f1b4Smrg _mesa_HashLookup(ctx->Shared->TexObjects, id); 607117f1b4Smrg} 617117f1b4Smrg 627117f1b4Smrg 637117f1b4Smrg 647117f1b4Smrg/** 657117f1b4Smrg * Allocate and initialize a new texture object. But don't put it into the 667117f1b4Smrg * texture object hash table. 677117f1b4Smrg * 687117f1b4Smrg * Called via ctx->Driver.NewTextureObject, unless overridden by a device 697117f1b4Smrg * driver. 707117f1b4Smrg * 717117f1b4Smrg * \param shared the shared GL state structure to contain the texture object 727117f1b4Smrg * \param name integer name for the texture object 737117f1b4Smrg * \param target either GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, 747117f1b4Smrg * GL_TEXTURE_CUBE_MAP_ARB or GL_TEXTURE_RECTANGLE_NV. zero is ok for the sake 757117f1b4Smrg * of GenTextures() 767117f1b4Smrg * 777117f1b4Smrg * \return pointer to new texture object. 787117f1b4Smrg */ 797117f1b4Smrgstruct gl_texture_object * 807117f1b4Smrg_mesa_new_texture_object( GLcontext *ctx, GLuint name, GLenum target ) 817117f1b4Smrg{ 827117f1b4Smrg struct gl_texture_object *obj; 837117f1b4Smrg (void) ctx; 847117f1b4Smrg obj = MALLOC_STRUCT(gl_texture_object); 857117f1b4Smrg _mesa_initialize_texture_object(obj, name, target); 867117f1b4Smrg return obj; 877117f1b4Smrg} 887117f1b4Smrg 897117f1b4Smrg 907117f1b4Smrg/** 917117f1b4Smrg * Initialize a new texture object to default values. 927117f1b4Smrg * \param obj the texture object 937117f1b4Smrg * \param name the texture name 947117f1b4Smrg * \param target the texture target 957117f1b4Smrg */ 967117f1b4Smrgvoid 977117f1b4Smrg_mesa_initialize_texture_object( struct gl_texture_object *obj, 987117f1b4Smrg GLuint name, GLenum target ) 997117f1b4Smrg{ 1007117f1b4Smrg ASSERT(target == 0 || 1017117f1b4Smrg target == GL_TEXTURE_1D || 1027117f1b4Smrg target == GL_TEXTURE_2D || 1037117f1b4Smrg target == GL_TEXTURE_3D || 1047117f1b4Smrg target == GL_TEXTURE_CUBE_MAP_ARB || 105c1f859d4Smrg target == GL_TEXTURE_RECTANGLE_NV || 106c1f859d4Smrg target == GL_TEXTURE_1D_ARRAY_EXT || 107c1f859d4Smrg target == GL_TEXTURE_2D_ARRAY_EXT); 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 */ 141c1f859d4Smrg} 142c1f859d4Smrg 143c1f859d4Smrg 144c1f859d4Smrg/** 145c1f859d4Smrg * Some texture initialization can't be finished until we know which 146c1f859d4Smrg * target it's getting bound to (GL_TEXTURE_1D/2D/etc). 147c1f859d4Smrg */ 148c1f859d4Smrgstatic void 149c1f859d4Smrgfinish_texture_init(GLcontext *ctx, GLenum target, 150c1f859d4Smrg struct gl_texture_object *obj) 151c1f859d4Smrg{ 152c1f859d4Smrg assert(obj->Target == 0); 153c1f859d4Smrg 154c1f859d4Smrg if (target == GL_TEXTURE_RECTANGLE_NV) { 155c1f859d4Smrg /* have to init wrap and filter state here - kind of klunky */ 156c1f859d4Smrg obj->WrapS = GL_CLAMP_TO_EDGE; 157c1f859d4Smrg obj->WrapT = GL_CLAMP_TO_EDGE; 158c1f859d4Smrg obj->WrapR = GL_CLAMP_TO_EDGE; 159c1f859d4Smrg obj->MinFilter = GL_LINEAR; 160c1f859d4Smrg if (ctx->Driver.TexParameter) { 161c1f859d4Smrg static const GLfloat fparam_wrap[1] = {(GLfloat) GL_CLAMP_TO_EDGE}; 162c1f859d4Smrg static const GLfloat fparam_filter[1] = {(GLfloat) GL_LINEAR}; 163c1f859d4Smrg ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_S, fparam_wrap); 164c1f859d4Smrg ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_T, fparam_wrap); 165c1f859d4Smrg ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_R, fparam_wrap); 166c1f859d4Smrg ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_MIN_FILTER, fparam_filter); 167c1f859d4Smrg } 168c1f859d4Smrg } 1697117f1b4Smrg} 1707117f1b4Smrg 1717117f1b4Smrg 1727117f1b4Smrg/** 1737117f1b4Smrg * Deallocate a texture object struct. It should have already been 1747117f1b4Smrg * removed from the texture object pool. 175c1f859d4Smrg * Called via ctx->Driver.DeleteTexture() if not overriden by a driver. 1767117f1b4Smrg * 1777117f1b4Smrg * \param shared the shared GL state to which the object belongs. 1787117f1b4Smrg * \param texOjb the texture object to delete. 1797117f1b4Smrg */ 1807117f1b4Smrgvoid 1817117f1b4Smrg_mesa_delete_texture_object( GLcontext *ctx, struct gl_texture_object *texObj ) 1827117f1b4Smrg{ 1837117f1b4Smrg GLuint i, face; 1847117f1b4Smrg 1857117f1b4Smrg (void) ctx; 1867117f1b4Smrg 1877117f1b4Smrg /* Set Target to an invalid value. With some assertions elsewhere 1887117f1b4Smrg * we can try to detect possible use of deleted textures. 1897117f1b4Smrg */ 1907117f1b4Smrg texObj->Target = 0x99; 1917117f1b4Smrg 192c1f859d4Smrg#if FEATURE_colortable 1937117f1b4Smrg _mesa_free_colortable_data(&texObj->Palette); 194c1f859d4Smrg#endif 1957117f1b4Smrg 1967117f1b4Smrg /* free the texture images */ 1977117f1b4Smrg for (face = 0; face < 6; face++) { 1987117f1b4Smrg for (i = 0; i < MAX_TEXTURE_LEVELS; i++) { 1997117f1b4Smrg if (texObj->Image[face][i]) { 2007117f1b4Smrg _mesa_delete_texture_image( ctx, texObj->Image[face][i] ); 2017117f1b4Smrg } 2027117f1b4Smrg } 2037117f1b4Smrg } 2047117f1b4Smrg 2057117f1b4Smrg /* destroy the mutex -- it may have allocated memory (eg on bsd) */ 2067117f1b4Smrg _glthread_DESTROY_MUTEX(texObj->Mutex); 2077117f1b4Smrg 2087117f1b4Smrg /* free this object */ 2097117f1b4Smrg _mesa_free(texObj); 2107117f1b4Smrg} 2117117f1b4Smrg 2127117f1b4Smrg 2137117f1b4Smrg 2147117f1b4Smrg 2157117f1b4Smrg/** 2167117f1b4Smrg * Copy texture object state from one texture object to another. 2177117f1b4Smrg * Use for glPush/PopAttrib. 2187117f1b4Smrg * 2197117f1b4Smrg * \param dest destination texture object. 2207117f1b4Smrg * \param src source texture object. 2217117f1b4Smrg */ 2227117f1b4Smrgvoid 2237117f1b4Smrg_mesa_copy_texture_object( struct gl_texture_object *dest, 2247117f1b4Smrg const struct gl_texture_object *src ) 2257117f1b4Smrg{ 2267117f1b4Smrg dest->Target = src->Target; 2277117f1b4Smrg dest->Name = src->Name; 2287117f1b4Smrg dest->Priority = src->Priority; 2297117f1b4Smrg dest->BorderColor[0] = src->BorderColor[0]; 2307117f1b4Smrg dest->BorderColor[1] = src->BorderColor[1]; 2317117f1b4Smrg dest->BorderColor[2] = src->BorderColor[2]; 2327117f1b4Smrg dest->BorderColor[3] = src->BorderColor[3]; 2337117f1b4Smrg dest->WrapS = src->WrapS; 2347117f1b4Smrg dest->WrapT = src->WrapT; 2357117f1b4Smrg dest->WrapR = src->WrapR; 2367117f1b4Smrg dest->MinFilter = src->MinFilter; 2377117f1b4Smrg dest->MagFilter = src->MagFilter; 2387117f1b4Smrg dest->MinLod = src->MinLod; 2397117f1b4Smrg dest->MaxLod = src->MaxLod; 2407117f1b4Smrg dest->LodBias = src->LodBias; 2417117f1b4Smrg dest->BaseLevel = src->BaseLevel; 2427117f1b4Smrg dest->MaxLevel = src->MaxLevel; 2437117f1b4Smrg dest->MaxAnisotropy = src->MaxAnisotropy; 2447117f1b4Smrg dest->CompareFlag = src->CompareFlag; 2457117f1b4Smrg dest->CompareOperator = src->CompareOperator; 2467117f1b4Smrg dest->ShadowAmbient = src->ShadowAmbient; 2477117f1b4Smrg dest->CompareMode = src->CompareMode; 2487117f1b4Smrg dest->CompareFunc = src->CompareFunc; 2497117f1b4Smrg dest->DepthMode = src->DepthMode; 2507117f1b4Smrg dest->_MaxLevel = src->_MaxLevel; 2517117f1b4Smrg dest->_MaxLambda = src->_MaxLambda; 2527117f1b4Smrg dest->GenerateMipmap = src->GenerateMipmap; 2537117f1b4Smrg dest->Palette = src->Palette; 254c1f859d4Smrg dest->_Complete = src->_Complete; 2557117f1b4Smrg} 2567117f1b4Smrg 2577117f1b4Smrg 2587117f1b4Smrg/** 2597117f1b4Smrg * Check if the given texture object is valid by examining its Target field. 2607117f1b4Smrg * For debugging only. 2617117f1b4Smrg */ 2627117f1b4Smrgstatic GLboolean 2637117f1b4Smrgvalid_texture_object(const struct gl_texture_object *tex) 2647117f1b4Smrg{ 2657117f1b4Smrg switch (tex->Target) { 2667117f1b4Smrg case 0: 2677117f1b4Smrg case GL_TEXTURE_1D: 2687117f1b4Smrg case GL_TEXTURE_2D: 2697117f1b4Smrg case GL_TEXTURE_3D: 2707117f1b4Smrg case GL_TEXTURE_CUBE_MAP_ARB: 2717117f1b4Smrg case GL_TEXTURE_RECTANGLE_NV: 272c1f859d4Smrg case GL_TEXTURE_1D_ARRAY_EXT: 273c1f859d4Smrg case GL_TEXTURE_2D_ARRAY_EXT: 2747117f1b4Smrg return GL_TRUE; 2757117f1b4Smrg case 0x99: 2767117f1b4Smrg _mesa_problem(NULL, "invalid reference to a deleted texture object"); 2777117f1b4Smrg return GL_FALSE; 2787117f1b4Smrg default: 2797117f1b4Smrg _mesa_problem(NULL, "invalid texture object Target value"); 2807117f1b4Smrg return GL_FALSE; 2817117f1b4Smrg } 2827117f1b4Smrg} 2837117f1b4Smrg 2847117f1b4Smrg 2857117f1b4Smrg/** 2867117f1b4Smrg * Reference (or unreference) a texture object. 2877117f1b4Smrg * If '*ptr', decrement *ptr's refcount (and delete if it becomes zero). 2887117f1b4Smrg * If 'tex' is non-null, increment its refcount. 2897117f1b4Smrg */ 2907117f1b4Smrgvoid 2917117f1b4Smrg_mesa_reference_texobj(struct gl_texture_object **ptr, 2927117f1b4Smrg struct gl_texture_object *tex) 2937117f1b4Smrg{ 2947117f1b4Smrg assert(ptr); 2957117f1b4Smrg if (*ptr == tex) { 2967117f1b4Smrg /* no change */ 2977117f1b4Smrg return; 2987117f1b4Smrg } 2997117f1b4Smrg 3007117f1b4Smrg if (*ptr) { 3017117f1b4Smrg /* Unreference the old texture */ 3027117f1b4Smrg GLboolean deleteFlag = GL_FALSE; 3037117f1b4Smrg struct gl_texture_object *oldTex = *ptr; 3047117f1b4Smrg 3057117f1b4Smrg assert(valid_texture_object(oldTex)); 3067117f1b4Smrg 3077117f1b4Smrg _glthread_LOCK_MUTEX(oldTex->Mutex); 3087117f1b4Smrg ASSERT(oldTex->RefCount > 0); 3097117f1b4Smrg oldTex->RefCount--; 3107117f1b4Smrg 3117117f1b4Smrg deleteFlag = (oldTex->RefCount == 0); 3127117f1b4Smrg _glthread_UNLOCK_MUTEX(oldTex->Mutex); 3137117f1b4Smrg 3147117f1b4Smrg if (deleteFlag) { 3157117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 3167117f1b4Smrg if (ctx) 3177117f1b4Smrg ctx->Driver.DeleteTexture(ctx, oldTex); 3187117f1b4Smrg else 3197117f1b4Smrg _mesa_problem(NULL, "Unable to delete texture, no context"); 3207117f1b4Smrg } 3217117f1b4Smrg 3227117f1b4Smrg *ptr = NULL; 3237117f1b4Smrg } 3247117f1b4Smrg assert(!*ptr); 3257117f1b4Smrg 3267117f1b4Smrg if (tex) { 3277117f1b4Smrg /* reference new texture */ 3287117f1b4Smrg assert(valid_texture_object(tex)); 3297117f1b4Smrg _glthread_LOCK_MUTEX(tex->Mutex); 3307117f1b4Smrg if (tex->RefCount == 0) { 3317117f1b4Smrg /* this texture's being deleted (look just above) */ 3327117f1b4Smrg /* Not sure this can every really happen. Warn if it does. */ 3337117f1b4Smrg _mesa_problem(NULL, "referencing deleted texture object"); 3347117f1b4Smrg *ptr = NULL; 3357117f1b4Smrg } 3367117f1b4Smrg else { 3377117f1b4Smrg tex->RefCount++; 3387117f1b4Smrg *ptr = tex; 3397117f1b4Smrg } 3407117f1b4Smrg _glthread_UNLOCK_MUTEX(tex->Mutex); 3417117f1b4Smrg } 3427117f1b4Smrg} 3437117f1b4Smrg 3447117f1b4Smrg 3457117f1b4Smrg 3467117f1b4Smrg/** 3477117f1b4Smrg * Report why a texture object is incomplete. 3487117f1b4Smrg * 3497117f1b4Smrg * \param t texture object. 3507117f1b4Smrg * \param why string describing why it's incomplete. 3517117f1b4Smrg * 3527117f1b4Smrg * \note For debug purposes only. 3537117f1b4Smrg */ 3547117f1b4Smrg#if 0 3557117f1b4Smrgstatic void 3567117f1b4Smrgincomplete(const struct gl_texture_object *t, const char *why) 3577117f1b4Smrg{ 3587117f1b4Smrg _mesa_printf("Texture Obj %d incomplete because: %s\n", t->Name, why); 3597117f1b4Smrg} 3607117f1b4Smrg#else 3617117f1b4Smrg#define incomplete(t, why) 3627117f1b4Smrg#endif 3637117f1b4Smrg 3647117f1b4Smrg 3657117f1b4Smrg/** 3667117f1b4Smrg * Examine a texture object to determine if it is complete. 3677117f1b4Smrg * 3687117f1b4Smrg * The gl_texture_object::Complete flag will be set to GL_TRUE or GL_FALSE 3697117f1b4Smrg * accordingly. 3707117f1b4Smrg * 3717117f1b4Smrg * \param ctx GL context. 3727117f1b4Smrg * \param t texture object. 3737117f1b4Smrg * 3747117f1b4Smrg * According to the texture target, verifies that each of the mipmaps is 3757117f1b4Smrg * present and has the expected size. 3767117f1b4Smrg */ 3777117f1b4Smrgvoid 3787117f1b4Smrg_mesa_test_texobj_completeness( const GLcontext *ctx, 3797117f1b4Smrg struct gl_texture_object *t ) 3807117f1b4Smrg{ 3817117f1b4Smrg const GLint baseLevel = t->BaseLevel; 3827117f1b4Smrg GLint maxLog2 = 0, maxLevels = 0; 3837117f1b4Smrg 384c1f859d4Smrg t->_Complete = GL_TRUE; /* be optimistic */ 385c1f859d4Smrg 386c1f859d4Smrg /* Detect cases where the application set the base level to an invalid 387c1f859d4Smrg * value. 388c1f859d4Smrg */ 389c1f859d4Smrg if ((baseLevel < 0) || (baseLevel > MAX_TEXTURE_LEVELS)) { 390c1f859d4Smrg char s[100]; 391c1f859d4Smrg _mesa_sprintf(s, "obj %p (%d) base level = %d is invalid", 392c1f859d4Smrg (void *) t, t->Name, baseLevel); 393c1f859d4Smrg incomplete(t, s); 394c1f859d4Smrg t->_Complete = GL_FALSE; 395c1f859d4Smrg return; 396c1f859d4Smrg } 3977117f1b4Smrg 3987117f1b4Smrg /* Always need the base level image */ 3997117f1b4Smrg if (!t->Image[0][baseLevel]) { 4007117f1b4Smrg char s[100]; 4017117f1b4Smrg _mesa_sprintf(s, "obj %p (%d) Image[baseLevel=%d] == NULL", 4027117f1b4Smrg (void *) t, t->Name, baseLevel); 4037117f1b4Smrg incomplete(t, s); 404c1f859d4Smrg t->_Complete = GL_FALSE; 4057117f1b4Smrg return; 4067117f1b4Smrg } 4077117f1b4Smrg 4087117f1b4Smrg /* Check width/height/depth for zero */ 4097117f1b4Smrg if (t->Image[0][baseLevel]->Width == 0 || 4107117f1b4Smrg t->Image[0][baseLevel]->Height == 0 || 4117117f1b4Smrg t->Image[0][baseLevel]->Depth == 0) { 4127117f1b4Smrg incomplete(t, "texture width = 0"); 413c1f859d4Smrg t->_Complete = GL_FALSE; 4147117f1b4Smrg return; 4157117f1b4Smrg } 4167117f1b4Smrg 4177117f1b4Smrg /* Compute _MaxLevel */ 418c1f859d4Smrg if ((t->Target == GL_TEXTURE_1D) || 419c1f859d4Smrg (t->Target == GL_TEXTURE_1D_ARRAY_EXT)) { 4207117f1b4Smrg maxLog2 = t->Image[0][baseLevel]->WidthLog2; 4217117f1b4Smrg maxLevels = ctx->Const.MaxTextureLevels; 4227117f1b4Smrg } 423c1f859d4Smrg else if ((t->Target == GL_TEXTURE_2D) || 424c1f859d4Smrg (t->Target == GL_TEXTURE_2D_ARRAY_EXT)) { 4257117f1b4Smrg maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2, 4267117f1b4Smrg t->Image[0][baseLevel]->HeightLog2); 4277117f1b4Smrg maxLevels = ctx->Const.MaxTextureLevels; 4287117f1b4Smrg } 4297117f1b4Smrg else if (t->Target == GL_TEXTURE_3D) { 4307117f1b4Smrg GLint max = MAX2(t->Image[0][baseLevel]->WidthLog2, 4317117f1b4Smrg t->Image[0][baseLevel]->HeightLog2); 4327117f1b4Smrg maxLog2 = MAX2(max, (GLint)(t->Image[0][baseLevel]->DepthLog2)); 4337117f1b4Smrg maxLevels = ctx->Const.Max3DTextureLevels; 4347117f1b4Smrg } 4357117f1b4Smrg else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) { 4367117f1b4Smrg maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2, 4377117f1b4Smrg t->Image[0][baseLevel]->HeightLog2); 4387117f1b4Smrg maxLevels = ctx->Const.MaxCubeTextureLevels; 4397117f1b4Smrg } 4407117f1b4Smrg else if (t->Target == GL_TEXTURE_RECTANGLE_NV) { 4417117f1b4Smrg maxLog2 = 0; /* not applicable */ 4427117f1b4Smrg maxLevels = 1; /* no mipmapping */ 4437117f1b4Smrg } 4447117f1b4Smrg else { 4457117f1b4Smrg _mesa_problem(ctx, "Bad t->Target in _mesa_test_texobj_completeness"); 4467117f1b4Smrg return; 4477117f1b4Smrg } 4487117f1b4Smrg 4497117f1b4Smrg ASSERT(maxLevels > 0); 4507117f1b4Smrg 4517117f1b4Smrg t->_MaxLevel = baseLevel + maxLog2; 4527117f1b4Smrg t->_MaxLevel = MIN2(t->_MaxLevel, t->MaxLevel); 4537117f1b4Smrg t->_MaxLevel = MIN2(t->_MaxLevel, maxLevels - 1); 4547117f1b4Smrg 4557117f1b4Smrg /* Compute _MaxLambda = q - b (see the 1.2 spec) used during mipmapping */ 4567117f1b4Smrg t->_MaxLambda = (GLfloat) (t->_MaxLevel - t->BaseLevel); 4577117f1b4Smrg 4587117f1b4Smrg if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) { 4597117f1b4Smrg /* make sure that all six cube map level 0 images are the same size */ 4607117f1b4Smrg const GLuint w = t->Image[0][baseLevel]->Width2; 4617117f1b4Smrg const GLuint h = t->Image[0][baseLevel]->Height2; 4627117f1b4Smrg GLuint face; 4637117f1b4Smrg for (face = 1; face < 6; face++) { 4647117f1b4Smrg if (t->Image[face][baseLevel] == NULL || 4657117f1b4Smrg t->Image[face][baseLevel]->Width2 != w || 4667117f1b4Smrg t->Image[face][baseLevel]->Height2 != h) { 467c1f859d4Smrg t->_Complete = GL_FALSE; 4687117f1b4Smrg incomplete(t, "Non-quare cubemap image"); 4697117f1b4Smrg return; 4707117f1b4Smrg } 4717117f1b4Smrg } 4727117f1b4Smrg } 4737117f1b4Smrg 4747117f1b4Smrg /* extra checking for mipmaps */ 4757117f1b4Smrg if (t->MinFilter != GL_NEAREST && t->MinFilter != GL_LINEAR) { 4767117f1b4Smrg /* 4777117f1b4Smrg * Mipmapping: determine if we have a complete set of mipmaps 4787117f1b4Smrg */ 4797117f1b4Smrg GLint i; 4807117f1b4Smrg GLint minLevel = baseLevel; 4817117f1b4Smrg GLint maxLevel = t->_MaxLevel; 4827117f1b4Smrg 4837117f1b4Smrg if (minLevel > maxLevel) { 484c1f859d4Smrg t->_Complete = GL_FALSE; 4857117f1b4Smrg incomplete(t, "minLevel > maxLevel"); 4867117f1b4Smrg return; 4877117f1b4Smrg } 4887117f1b4Smrg 4897117f1b4Smrg /* Test dimension-independent attributes */ 4907117f1b4Smrg for (i = minLevel; i <= maxLevel; i++) { 4917117f1b4Smrg if (t->Image[0][i]) { 4927117f1b4Smrg if (t->Image[0][i]->TexFormat != t->Image[0][baseLevel]->TexFormat) { 493c1f859d4Smrg t->_Complete = GL_FALSE; 4947117f1b4Smrg incomplete(t, "Format[i] != Format[baseLevel]"); 4957117f1b4Smrg return; 4967117f1b4Smrg } 4977117f1b4Smrg if (t->Image[0][i]->Border != t->Image[0][baseLevel]->Border) { 498c1f859d4Smrg t->_Complete = GL_FALSE; 4997117f1b4Smrg incomplete(t, "Border[i] != Border[baseLevel]"); 5007117f1b4Smrg return; 5017117f1b4Smrg } 5027117f1b4Smrg } 5037117f1b4Smrg } 5047117f1b4Smrg 5057117f1b4Smrg /* Test things which depend on number of texture image dimensions */ 506c1f859d4Smrg if ((t->Target == GL_TEXTURE_1D) || 507c1f859d4Smrg (t->Target == GL_TEXTURE_1D_ARRAY_EXT)) { 5087117f1b4Smrg /* Test 1-D mipmaps */ 5097117f1b4Smrg GLuint width = t->Image[0][baseLevel]->Width2; 5107117f1b4Smrg for (i = baseLevel + 1; i < maxLevels; i++) { 5117117f1b4Smrg if (width > 1) { 5127117f1b4Smrg width /= 2; 5137117f1b4Smrg } 5147117f1b4Smrg if (i >= minLevel && i <= maxLevel) { 5157117f1b4Smrg if (!t->Image[0][i]) { 516c1f859d4Smrg t->_Complete = GL_FALSE; 5177117f1b4Smrg incomplete(t, "1D Image[0][i] == NULL"); 5187117f1b4Smrg return; 5197117f1b4Smrg } 5207117f1b4Smrg if (t->Image[0][i]->Width2 != width ) { 521c1f859d4Smrg t->_Complete = GL_FALSE; 5227117f1b4Smrg incomplete(t, "1D Image[0][i] bad width"); 5237117f1b4Smrg return; 5247117f1b4Smrg } 5257117f1b4Smrg } 5267117f1b4Smrg if (width == 1) { 5277117f1b4Smrg return; /* found smallest needed mipmap, all done! */ 5287117f1b4Smrg } 5297117f1b4Smrg } 5307117f1b4Smrg } 531c1f859d4Smrg else if ((t->Target == GL_TEXTURE_2D) || 532c1f859d4Smrg (t->Target == GL_TEXTURE_2D_ARRAY_EXT)) { 5337117f1b4Smrg /* Test 2-D mipmaps */ 5347117f1b4Smrg GLuint width = t->Image[0][baseLevel]->Width2; 5357117f1b4Smrg GLuint height = t->Image[0][baseLevel]->Height2; 5367117f1b4Smrg for (i = baseLevel + 1; i < maxLevels; i++) { 5377117f1b4Smrg if (width > 1) { 5387117f1b4Smrg width /= 2; 5397117f1b4Smrg } 5407117f1b4Smrg if (height > 1) { 5417117f1b4Smrg height /= 2; 5427117f1b4Smrg } 5437117f1b4Smrg if (i >= minLevel && i <= maxLevel) { 5447117f1b4Smrg if (!t->Image[0][i]) { 545c1f859d4Smrg t->_Complete = GL_FALSE; 5467117f1b4Smrg incomplete(t, "2D Image[0][i] == NULL"); 5477117f1b4Smrg return; 5487117f1b4Smrg } 5497117f1b4Smrg if (t->Image[0][i]->Width2 != width) { 550c1f859d4Smrg t->_Complete = GL_FALSE; 5517117f1b4Smrg incomplete(t, "2D Image[0][i] bad width"); 5527117f1b4Smrg return; 5537117f1b4Smrg } 5547117f1b4Smrg if (t->Image[0][i]->Height2 != height) { 555c1f859d4Smrg t->_Complete = GL_FALSE; 5567117f1b4Smrg incomplete(t, "2D Image[0][i] bad height"); 5577117f1b4Smrg return; 5587117f1b4Smrg } 5597117f1b4Smrg if (width==1 && height==1) { 5607117f1b4Smrg return; /* found smallest needed mipmap, all done! */ 5617117f1b4Smrg } 5627117f1b4Smrg } 5637117f1b4Smrg } 5647117f1b4Smrg } 5657117f1b4Smrg else if (t->Target == GL_TEXTURE_3D) { 5667117f1b4Smrg /* Test 3-D mipmaps */ 5677117f1b4Smrg GLuint width = t->Image[0][baseLevel]->Width2; 5687117f1b4Smrg GLuint height = t->Image[0][baseLevel]->Height2; 5697117f1b4Smrg GLuint depth = t->Image[0][baseLevel]->Depth2; 5707117f1b4Smrg for (i = baseLevel + 1; i < maxLevels; i++) { 5717117f1b4Smrg if (width > 1) { 5727117f1b4Smrg width /= 2; 5737117f1b4Smrg } 5747117f1b4Smrg if (height > 1) { 5757117f1b4Smrg height /= 2; 5767117f1b4Smrg } 5777117f1b4Smrg if (depth > 1) { 5787117f1b4Smrg depth /= 2; 5797117f1b4Smrg } 5807117f1b4Smrg if (i >= minLevel && i <= maxLevel) { 5817117f1b4Smrg if (!t->Image[0][i]) { 5827117f1b4Smrg incomplete(t, "3D Image[0][i] == NULL"); 583c1f859d4Smrg t->_Complete = GL_FALSE; 5847117f1b4Smrg return; 5857117f1b4Smrg } 5867117f1b4Smrg if (t->Image[0][i]->_BaseFormat == GL_DEPTH_COMPONENT) { 587c1f859d4Smrg t->_Complete = GL_FALSE; 5887117f1b4Smrg incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex"); 5897117f1b4Smrg return; 5907117f1b4Smrg } 5917117f1b4Smrg if (t->Image[0][i]->Width2 != width) { 592c1f859d4Smrg t->_Complete = GL_FALSE; 5937117f1b4Smrg incomplete(t, "3D Image[0][i] bad width"); 5947117f1b4Smrg return; 5957117f1b4Smrg } 5967117f1b4Smrg if (t->Image[0][i]->Height2 != height) { 597c1f859d4Smrg t->_Complete = GL_FALSE; 5987117f1b4Smrg incomplete(t, "3D Image[0][i] bad height"); 5997117f1b4Smrg return; 6007117f1b4Smrg } 6017117f1b4Smrg if (t->Image[0][i]->Depth2 != depth) { 602c1f859d4Smrg t->_Complete = GL_FALSE; 6037117f1b4Smrg incomplete(t, "3D Image[0][i] bad depth"); 6047117f1b4Smrg return; 6057117f1b4Smrg } 6067117f1b4Smrg } 6077117f1b4Smrg if (width == 1 && height == 1 && depth == 1) { 6087117f1b4Smrg return; /* found smallest needed mipmap, all done! */ 6097117f1b4Smrg } 6107117f1b4Smrg } 6117117f1b4Smrg } 6127117f1b4Smrg else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) { 6137117f1b4Smrg /* make sure 6 cube faces are consistant */ 6147117f1b4Smrg GLuint width = t->Image[0][baseLevel]->Width2; 6157117f1b4Smrg GLuint height = t->Image[0][baseLevel]->Height2; 6167117f1b4Smrg for (i = baseLevel + 1; i < maxLevels; i++) { 6177117f1b4Smrg if (width > 1) { 6187117f1b4Smrg width /= 2; 6197117f1b4Smrg } 6207117f1b4Smrg if (height > 1) { 6217117f1b4Smrg height /= 2; 6227117f1b4Smrg } 6237117f1b4Smrg if (i >= minLevel && i <= maxLevel) { 6247117f1b4Smrg GLuint face; 6257117f1b4Smrg for (face = 0; face < 6; face++) { 6267117f1b4Smrg /* check that we have images defined */ 6277117f1b4Smrg if (!t->Image[face][i]) { 628c1f859d4Smrg t->_Complete = GL_FALSE; 6297117f1b4Smrg incomplete(t, "CubeMap Image[n][i] == NULL"); 6307117f1b4Smrg return; 6317117f1b4Smrg } 6327117f1b4Smrg /* Don't support GL_DEPTH_COMPONENT for cube maps */ 6337117f1b4Smrg if (t->Image[face][i]->_BaseFormat == GL_DEPTH_COMPONENT) { 634c1f859d4Smrg t->_Complete = GL_FALSE; 6357117f1b4Smrg incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex"); 6367117f1b4Smrg return; 6377117f1b4Smrg } 6387117f1b4Smrg /* check that all six images have same size */ 6397117f1b4Smrg if (t->Image[face][i]->Width2!=width || 6407117f1b4Smrg t->Image[face][i]->Height2!=height) { 641c1f859d4Smrg t->_Complete = GL_FALSE; 6427117f1b4Smrg incomplete(t, "CubeMap Image[n][i] bad size"); 6437117f1b4Smrg return; 6447117f1b4Smrg } 6457117f1b4Smrg } 6467117f1b4Smrg } 6477117f1b4Smrg if (width == 1 && height == 1) { 6487117f1b4Smrg return; /* found smallest needed mipmap, all done! */ 6497117f1b4Smrg } 6507117f1b4Smrg } 6517117f1b4Smrg } 6527117f1b4Smrg else if (t->Target == GL_TEXTURE_RECTANGLE_NV) { 6537117f1b4Smrg /* XXX special checking? */ 6547117f1b4Smrg } 6557117f1b4Smrg else { 6567117f1b4Smrg /* Target = ??? */ 6577117f1b4Smrg _mesa_problem(ctx, "Bug in gl_test_texture_object_completeness\n"); 6587117f1b4Smrg } 6597117f1b4Smrg } 6607117f1b4Smrg} 6617117f1b4Smrg 6627117f1b4Smrg/*@}*/ 6637117f1b4Smrg 6647117f1b4Smrg 6657117f1b4Smrg/***********************************************************************/ 6667117f1b4Smrg/** \name API functions */ 6677117f1b4Smrg/*@{*/ 6687117f1b4Smrg 6697117f1b4Smrg 6707117f1b4Smrg/** 6717117f1b4Smrg * Generate texture names. 6727117f1b4Smrg * 6737117f1b4Smrg * \param n number of texture names to be generated. 6747117f1b4Smrg * \param textures an array in which will hold the generated texture names. 6757117f1b4Smrg * 6767117f1b4Smrg * \sa glGenTextures(). 6777117f1b4Smrg * 678c1f859d4Smrg * Calls _mesa_HashFindFreeKeyBlock() to find a block of free texture 679c1f859d4Smrg * IDs which are stored in \p textures. Corresponding empty texture 680c1f859d4Smrg * objects are also generated. 6817117f1b4Smrg */ 6827117f1b4Smrgvoid GLAPIENTRY 6837117f1b4Smrg_mesa_GenTextures( GLsizei n, GLuint *textures ) 6847117f1b4Smrg{ 6857117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 6867117f1b4Smrg GLuint first; 6877117f1b4Smrg GLint i; 6887117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 6897117f1b4Smrg 6907117f1b4Smrg if (n < 0) { 6917117f1b4Smrg _mesa_error( ctx, GL_INVALID_VALUE, "glGenTextures" ); 6927117f1b4Smrg return; 6937117f1b4Smrg } 6947117f1b4Smrg 6957117f1b4Smrg if (!textures) 6967117f1b4Smrg return; 6977117f1b4Smrg 6987117f1b4Smrg /* 6997117f1b4Smrg * This must be atomic (generation and allocation of texture IDs) 7007117f1b4Smrg */ 701c1f859d4Smrg _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 7027117f1b4Smrg 7037117f1b4Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Shared->TexObjects, n); 7047117f1b4Smrg 7057117f1b4Smrg /* Allocate new, empty texture objects */ 7067117f1b4Smrg for (i = 0; i < n; i++) { 7077117f1b4Smrg struct gl_texture_object *texObj; 7087117f1b4Smrg GLuint name = first + i; 7097117f1b4Smrg GLenum target = 0; 7107117f1b4Smrg texObj = (*ctx->Driver.NewTextureObject)( ctx, name, target); 7117117f1b4Smrg if (!texObj) { 712c1f859d4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 7137117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures"); 7147117f1b4Smrg return; 7157117f1b4Smrg } 7167117f1b4Smrg 7177117f1b4Smrg /* insert into hash table */ 7187117f1b4Smrg _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj); 7197117f1b4Smrg 7207117f1b4Smrg textures[i] = name; 7217117f1b4Smrg } 7227117f1b4Smrg 723c1f859d4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 7247117f1b4Smrg} 7257117f1b4Smrg 7267117f1b4Smrg 7277117f1b4Smrg/** 7287117f1b4Smrg * Check if the given texture object is bound to the current draw or 7297117f1b4Smrg * read framebuffer. If so, Unbind it. 7307117f1b4Smrg */ 7317117f1b4Smrgstatic void 7327117f1b4Smrgunbind_texobj_from_fbo(GLcontext *ctx, struct gl_texture_object *texObj) 7337117f1b4Smrg{ 7347117f1b4Smrg const GLuint n = (ctx->DrawBuffer == ctx->ReadBuffer) ? 1 : 2; 7357117f1b4Smrg GLuint i; 7367117f1b4Smrg 7377117f1b4Smrg for (i = 0; i < n; i++) { 7387117f1b4Smrg struct gl_framebuffer *fb = (i == 0) ? ctx->DrawBuffer : ctx->ReadBuffer; 7397117f1b4Smrg if (fb->Name) { 7407117f1b4Smrg GLuint j; 7417117f1b4Smrg for (j = 0; j < BUFFER_COUNT; j++) { 7427117f1b4Smrg if (fb->Attachment[j].Type == GL_TEXTURE && 7437117f1b4Smrg fb->Attachment[j].Texture == texObj) { 7447117f1b4Smrg _mesa_remove_attachment(ctx, fb->Attachment + j); 7457117f1b4Smrg } 7467117f1b4Smrg } 7477117f1b4Smrg } 7487117f1b4Smrg } 7497117f1b4Smrg} 7507117f1b4Smrg 7517117f1b4Smrg 7527117f1b4Smrg/** 7537117f1b4Smrg * Check if the given texture object is bound to any texture image units and 7547117f1b4Smrg * unbind it if so (revert to default textures). 7557117f1b4Smrg */ 7567117f1b4Smrgstatic void 7577117f1b4Smrgunbind_texobj_from_texunits(GLcontext *ctx, struct gl_texture_object *texObj) 7587117f1b4Smrg{ 759c1f859d4Smrg GLuint u, tex; 7607117f1b4Smrg 7617117f1b4Smrg for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) { 7627117f1b4Smrg struct gl_texture_unit *unit = &ctx->Texture.Unit[u]; 763c1f859d4Smrg for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { 764c1f859d4Smrg if (texObj == unit->CurrentTex[tex]) { 765c1f859d4Smrg _mesa_reference_texobj(&unit->CurrentTex[tex], 766c1f859d4Smrg ctx->Shared->DefaultTex[TEXTURE_1D_INDEX]); 767c1f859d4Smrg ASSERT(unit->CurrentTex[tex]); 768c1f859d4Smrg break; 769c1f859d4Smrg } 7707117f1b4Smrg } 7717117f1b4Smrg } 7727117f1b4Smrg} 7737117f1b4Smrg 7747117f1b4Smrg 7757117f1b4Smrg/** 7767117f1b4Smrg * Delete named textures. 7777117f1b4Smrg * 7787117f1b4Smrg * \param n number of textures to be deleted. 7797117f1b4Smrg * \param textures array of texture IDs to be deleted. 7807117f1b4Smrg * 7817117f1b4Smrg * \sa glDeleteTextures(). 7827117f1b4Smrg * 7837117f1b4Smrg * If we're about to delete a texture that's currently bound to any 7847117f1b4Smrg * texture unit, unbind the texture first. Decrement the reference 7857117f1b4Smrg * count on the texture object and delete it if it's zero. 7867117f1b4Smrg * Recall that texture objects can be shared among several rendering 7877117f1b4Smrg * contexts. 7887117f1b4Smrg */ 7897117f1b4Smrgvoid GLAPIENTRY 7907117f1b4Smrg_mesa_DeleteTextures( GLsizei n, const GLuint *textures) 7917117f1b4Smrg{ 7927117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 7937117f1b4Smrg GLint i; 7947117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */ 7957117f1b4Smrg 7967117f1b4Smrg if (!textures) 7977117f1b4Smrg return; 7987117f1b4Smrg 7997117f1b4Smrg for (i = 0; i < n; i++) { 8007117f1b4Smrg if (textures[i] > 0) { 8017117f1b4Smrg struct gl_texture_object *delObj 8027117f1b4Smrg = _mesa_lookup_texture(ctx, textures[i]); 8037117f1b4Smrg 8047117f1b4Smrg if (delObj) { 8057117f1b4Smrg _mesa_lock_texture(ctx, delObj); 8067117f1b4Smrg 8077117f1b4Smrg /* Check if texture is bound to any framebuffer objects. 8087117f1b4Smrg * If so, unbind. 8097117f1b4Smrg * See section 4.4.2.3 of GL_EXT_framebuffer_object. 8107117f1b4Smrg */ 8117117f1b4Smrg unbind_texobj_from_fbo(ctx, delObj); 8127117f1b4Smrg 8137117f1b4Smrg /* Check if this texture is currently bound to any texture units. 8147117f1b4Smrg * If so, unbind it. 8157117f1b4Smrg */ 8167117f1b4Smrg unbind_texobj_from_texunits(ctx, delObj); 8177117f1b4Smrg 8187117f1b4Smrg _mesa_unlock_texture(ctx, delObj); 8197117f1b4Smrg 8207117f1b4Smrg ctx->NewState |= _NEW_TEXTURE; 8217117f1b4Smrg 8227117f1b4Smrg /* The texture _name_ is now free for re-use. 8237117f1b4Smrg * Remove it from the hash table now. 8247117f1b4Smrg */ 8257117f1b4Smrg _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 8267117f1b4Smrg _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name); 8277117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 8287117f1b4Smrg 8297117f1b4Smrg /* Unreference the texobj. If refcount hits zero, the texture 8307117f1b4Smrg * will be deleted. 8317117f1b4Smrg */ 8327117f1b4Smrg _mesa_reference_texobj(&delObj, NULL); 8337117f1b4Smrg } 8347117f1b4Smrg } 8357117f1b4Smrg } 8367117f1b4Smrg} 8377117f1b4Smrg 8387117f1b4Smrg 839c1f859d4Smrg/** 840c1f859d4Smrg * Convert a GL texture target enum such as GL_TEXTURE_2D or GL_TEXTURE_3D 841c1f859d4Smrg * into the corresponding Mesa texture target index. 842c1f859d4Smrg * Return -1 if target is invalid. 843c1f859d4Smrg */ 844c1f859d4Smrgstatic GLint 845c1f859d4Smrgtarget_enum_to_index(GLenum target) 846c1f859d4Smrg{ 847c1f859d4Smrg switch (target) { 848c1f859d4Smrg case GL_TEXTURE_1D: 849c1f859d4Smrg return TEXTURE_1D_INDEX; 850c1f859d4Smrg case GL_TEXTURE_2D: 851c1f859d4Smrg return TEXTURE_2D_INDEX; 852c1f859d4Smrg case GL_TEXTURE_3D: 853c1f859d4Smrg return TEXTURE_3D_INDEX; 854c1f859d4Smrg case GL_TEXTURE_CUBE_MAP_ARB: 855c1f859d4Smrg return TEXTURE_CUBE_INDEX; 856c1f859d4Smrg case GL_TEXTURE_RECTANGLE_NV: 857c1f859d4Smrg return TEXTURE_RECT_INDEX; 858c1f859d4Smrg case GL_TEXTURE_1D_ARRAY_EXT: 859c1f859d4Smrg return TEXTURE_1D_ARRAY_INDEX; 860c1f859d4Smrg case GL_TEXTURE_2D_ARRAY_EXT: 861c1f859d4Smrg return TEXTURE_2D_ARRAY_INDEX; 862c1f859d4Smrg default: 863c1f859d4Smrg return -1; 864c1f859d4Smrg } 865c1f859d4Smrg} 866c1f859d4Smrg 867c1f859d4Smrg 8687117f1b4Smrg/** 8697117f1b4Smrg * Bind a named texture to a texturing target. 8707117f1b4Smrg * 8717117f1b4Smrg * \param target texture target. 8727117f1b4Smrg * \param texName texture name. 8737117f1b4Smrg * 8747117f1b4Smrg * \sa glBindTexture(). 8757117f1b4Smrg * 8767117f1b4Smrg * Determines the old texture object bound and returns immediately if rebinding 8777117f1b4Smrg * the same texture. Get the current texture which is either a default texture 8787117f1b4Smrg * if name is null, a named texture from the hash, or a new texture if the 8797117f1b4Smrg * given texture name is new. Increments its reference count, binds it, and 8807117f1b4Smrg * calls dd_function_table::BindTexture. Decrements the old texture reference 8817117f1b4Smrg * count and deletes it if it reaches zero. 8827117f1b4Smrg */ 8837117f1b4Smrgvoid GLAPIENTRY 8847117f1b4Smrg_mesa_BindTexture( GLenum target, GLuint texName ) 8857117f1b4Smrg{ 8867117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 8877117f1b4Smrg const GLuint unit = ctx->Texture.CurrentUnit; 8887117f1b4Smrg struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; 889c1f859d4Smrg struct gl_texture_object *newTexObj = NULL, *defaultTexObj = NULL; 890c1f859d4Smrg GLint targetIndex; 8917117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 8927117f1b4Smrg 8937117f1b4Smrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 8947117f1b4Smrg _mesa_debug(ctx, "glBindTexture %s %d\n", 8957117f1b4Smrg _mesa_lookup_enum_by_nr(target), (GLint) texName); 8967117f1b4Smrg 897c1f859d4Smrg targetIndex = target_enum_to_index(target); 898c1f859d4Smrg if (targetIndex < 0) { 899c1f859d4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)"); 900c1f859d4Smrg return; 901c1f859d4Smrg } 902c1f859d4Smrg assert(targetIndex < NUM_TEXTURE_TARGETS); 903c1f859d4Smrg defaultTexObj = ctx->Shared->DefaultTex[targetIndex]; 904c1f859d4Smrg 9057117f1b4Smrg /* 9067117f1b4Smrg * Get pointer to new texture object (newTexObj) 9077117f1b4Smrg */ 9087117f1b4Smrg if (texName == 0) { 909c1f859d4Smrg newTexObj = defaultTexObj; 9107117f1b4Smrg } 9117117f1b4Smrg else { 9127117f1b4Smrg /* non-default texture object */ 9137117f1b4Smrg newTexObj = _mesa_lookup_texture(ctx, texName); 9147117f1b4Smrg if (newTexObj) { 9157117f1b4Smrg /* error checking */ 9167117f1b4Smrg if (newTexObj->Target != 0 && newTexObj->Target != target) { 917c1f859d4Smrg /* the named texture object's target doesn't match the given target */ 9187117f1b4Smrg _mesa_error( ctx, GL_INVALID_OPERATION, 919c1f859d4Smrg "glBindTexture(target mismatch)" ); 9207117f1b4Smrg return; 9217117f1b4Smrg } 922c1f859d4Smrg if (newTexObj->Target == 0) { 923c1f859d4Smrg finish_texture_init(ctx, target, newTexObj); 9247117f1b4Smrg } 9257117f1b4Smrg } 9267117f1b4Smrg else { 9277117f1b4Smrg /* if this is a new texture id, allocate a texture object now */ 9287117f1b4Smrg newTexObj = (*ctx->Driver.NewTextureObject)(ctx, texName, target); 9297117f1b4Smrg if (!newTexObj) { 9307117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture"); 9317117f1b4Smrg return; 9327117f1b4Smrg } 9337117f1b4Smrg 9347117f1b4Smrg /* and insert it into hash table */ 9357117f1b4Smrg _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 9367117f1b4Smrg _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj); 9377117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 9387117f1b4Smrg } 9397117f1b4Smrg newTexObj->Target = target; 9407117f1b4Smrg } 9417117f1b4Smrg 9427117f1b4Smrg assert(valid_texture_object(newTexObj)); 9437117f1b4Smrg 9447117f1b4Smrg /* flush before changing binding */ 9457117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_TEXTURE); 9467117f1b4Smrg 9477117f1b4Smrg /* Do the actual binding. The refcount on the previously bound 9487117f1b4Smrg * texture object will be decremented. It'll be deleted if the 9497117f1b4Smrg * count hits zero. 9507117f1b4Smrg */ 951c1f859d4Smrg _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], newTexObj); 952c1f859d4Smrg ASSERT(texUnit->CurrentTex[targetIndex]); 9537117f1b4Smrg 9547117f1b4Smrg /* Pass BindTexture call to device driver */ 9557117f1b4Smrg if (ctx->Driver.BindTexture) 9567117f1b4Smrg (*ctx->Driver.BindTexture)( ctx, target, newTexObj ); 9577117f1b4Smrg} 9587117f1b4Smrg 9597117f1b4Smrg 9607117f1b4Smrg/** 9617117f1b4Smrg * Set texture priorities. 9627117f1b4Smrg * 9637117f1b4Smrg * \param n number of textures. 9647117f1b4Smrg * \param texName texture names. 9657117f1b4Smrg * \param priorities corresponding texture priorities. 9667117f1b4Smrg * 9677117f1b4Smrg * \sa glPrioritizeTextures(). 9687117f1b4Smrg * 9697117f1b4Smrg * Looks up each texture in the hash, clamps the corresponding priority between 9707117f1b4Smrg * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture. 9717117f1b4Smrg */ 9727117f1b4Smrgvoid GLAPIENTRY 9737117f1b4Smrg_mesa_PrioritizeTextures( GLsizei n, const GLuint *texName, 9747117f1b4Smrg const GLclampf *priorities ) 9757117f1b4Smrg{ 9767117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 9777117f1b4Smrg GLint i; 9787117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 9797117f1b4Smrg 9807117f1b4Smrg if (n < 0) { 9817117f1b4Smrg _mesa_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" ); 9827117f1b4Smrg return; 9837117f1b4Smrg } 9847117f1b4Smrg 9857117f1b4Smrg if (!priorities) 9867117f1b4Smrg return; 9877117f1b4Smrg 9887117f1b4Smrg for (i = 0; i < n; i++) { 9897117f1b4Smrg if (texName[i] > 0) { 9907117f1b4Smrg struct gl_texture_object *t = _mesa_lookup_texture(ctx, texName[i]); 9917117f1b4Smrg if (t) { 9927117f1b4Smrg t->Priority = CLAMP( priorities[i], 0.0F, 1.0F ); 9937117f1b4Smrg if (ctx->Driver.PrioritizeTexture) 9947117f1b4Smrg ctx->Driver.PrioritizeTexture( ctx, t, t->Priority ); 9957117f1b4Smrg } 9967117f1b4Smrg } 9977117f1b4Smrg } 9987117f1b4Smrg 9997117f1b4Smrg ctx->NewState |= _NEW_TEXTURE; 10007117f1b4Smrg} 10017117f1b4Smrg 10027117f1b4Smrg/** 10037117f1b4Smrg * See if textures are loaded in texture memory. 10047117f1b4Smrg * 10057117f1b4Smrg * \param n number of textures to query. 10067117f1b4Smrg * \param texName array with the texture names. 10077117f1b4Smrg * \param residences array which will hold the residence status. 10087117f1b4Smrg * 10097117f1b4Smrg * \return GL_TRUE if all textures are resident and \p residences is left unchanged, 10107117f1b4Smrg * 10117117f1b4Smrg * \sa glAreTexturesResident(). 10127117f1b4Smrg * 10137117f1b4Smrg * Looks up each texture in the hash and calls 10147117f1b4Smrg * dd_function_table::IsTextureResident. 10157117f1b4Smrg */ 10167117f1b4SmrgGLboolean GLAPIENTRY 10177117f1b4Smrg_mesa_AreTexturesResident(GLsizei n, const GLuint *texName, 10187117f1b4Smrg GLboolean *residences) 10197117f1b4Smrg{ 10207117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 10217117f1b4Smrg GLboolean allResident = GL_TRUE; 10227117f1b4Smrg GLint i, j; 10237117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 10247117f1b4Smrg 10257117f1b4Smrg if (n < 0) { 10267117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)"); 10277117f1b4Smrg return GL_FALSE; 10287117f1b4Smrg } 10297117f1b4Smrg 10307117f1b4Smrg if (!texName || !residences) 10317117f1b4Smrg return GL_FALSE; 10327117f1b4Smrg 10337117f1b4Smrg for (i = 0; i < n; i++) { 10347117f1b4Smrg struct gl_texture_object *t; 10357117f1b4Smrg if (texName[i] == 0) { 10367117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident"); 10377117f1b4Smrg return GL_FALSE; 10387117f1b4Smrg } 10397117f1b4Smrg t = _mesa_lookup_texture(ctx, texName[i]); 10407117f1b4Smrg if (!t) { 10417117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident"); 10427117f1b4Smrg return GL_FALSE; 10437117f1b4Smrg } 10447117f1b4Smrg if (!ctx->Driver.IsTextureResident || 10457117f1b4Smrg ctx->Driver.IsTextureResident(ctx, t)) { 10467117f1b4Smrg /* The texture is resident */ 10477117f1b4Smrg if (!allResident) 10487117f1b4Smrg residences[i] = GL_TRUE; 10497117f1b4Smrg } 10507117f1b4Smrg else { 10517117f1b4Smrg /* The texture is not resident */ 10527117f1b4Smrg if (allResident) { 10537117f1b4Smrg allResident = GL_FALSE; 10547117f1b4Smrg for (j = 0; j < i; j++) 10557117f1b4Smrg residences[j] = GL_TRUE; 10567117f1b4Smrg } 10577117f1b4Smrg residences[i] = GL_FALSE; 10587117f1b4Smrg } 10597117f1b4Smrg } 10607117f1b4Smrg 10617117f1b4Smrg return allResident; 10627117f1b4Smrg} 10637117f1b4Smrg 10647117f1b4Smrg/** 10657117f1b4Smrg * See if a name corresponds to a texture. 10667117f1b4Smrg * 10677117f1b4Smrg * \param texture texture name. 10687117f1b4Smrg * 10697117f1b4Smrg * \return GL_TRUE if texture name corresponds to a texture, or GL_FALSE 10707117f1b4Smrg * otherwise. 10717117f1b4Smrg * 10727117f1b4Smrg * \sa glIsTexture(). 10737117f1b4Smrg * 10747117f1b4Smrg * Calls _mesa_HashLookup(). 10757117f1b4Smrg */ 10767117f1b4SmrgGLboolean GLAPIENTRY 10777117f1b4Smrg_mesa_IsTexture( GLuint texture ) 10787117f1b4Smrg{ 10797117f1b4Smrg struct gl_texture_object *t; 10807117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 10817117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 10827117f1b4Smrg 10837117f1b4Smrg if (!texture) 10847117f1b4Smrg return GL_FALSE; 10857117f1b4Smrg 10867117f1b4Smrg t = _mesa_lookup_texture(ctx, texture); 10877117f1b4Smrg 10887117f1b4Smrg /* IsTexture is true only after object has been bound once. */ 10897117f1b4Smrg return t && t->Target; 10907117f1b4Smrg} 10917117f1b4Smrg 1092c1f859d4Smrg 1093c1f859d4Smrg/** 1094c1f859d4Smrg * Simplest implementation of texture locking: Grab the a new mutex in 10957117f1b4Smrg * the shared context. Examine the shared context state timestamp and 10967117f1b4Smrg * if there has been a change, set the appropriate bits in 10977117f1b4Smrg * ctx->NewState. 10987117f1b4Smrg * 1099c1f859d4Smrg * This is used to deal with synchronizing things when a texture object 1100c1f859d4Smrg * is used/modified by different contexts (or threads) which are sharing 1101c1f859d4Smrg * the texture. 1102c1f859d4Smrg * 1103c1f859d4Smrg * See also _mesa_lock/unlock_texture() in teximage.h 11047117f1b4Smrg */ 1105c1f859d4Smrgvoid 1106c1f859d4Smrg_mesa_lock_context_textures( GLcontext *ctx ) 11077117f1b4Smrg{ 11087117f1b4Smrg _glthread_LOCK_MUTEX(ctx->Shared->TexMutex); 11097117f1b4Smrg 11107117f1b4Smrg if (ctx->Shared->TextureStateStamp != ctx->TextureStateTimestamp) { 11117117f1b4Smrg ctx->NewState |= _NEW_TEXTURE; 11127117f1b4Smrg ctx->TextureStateTimestamp = ctx->Shared->TextureStateStamp; 11137117f1b4Smrg } 11147117f1b4Smrg} 11157117f1b4Smrg 11167117f1b4Smrg 1117c1f859d4Smrgvoid 1118c1f859d4Smrg_mesa_unlock_context_textures( GLcontext *ctx ) 11197117f1b4Smrg{ 11207117f1b4Smrg assert(ctx->Shared->TextureStateStamp == ctx->TextureStateTimestamp); 11217117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->TexMutex); 11227117f1b4Smrg} 11237117f1b4Smrg 11247117f1b4Smrg/*@}*/ 11257117f1b4Smrg 11267117f1b4Smrg 1127