texobj.c revision 4a49301e
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 314a49301eSmrg#include "mfeatures.h" 327117f1b4Smrg#include "colortab.h" 337117f1b4Smrg#include "context.h" 347117f1b4Smrg#include "enums.h" 357117f1b4Smrg#include "fbobject.h" 364a49301eSmrg#include "formats.h" 377117f1b4Smrg#include "hash.h" 387117f1b4Smrg#include "imports.h" 397117f1b4Smrg#include "macros.h" 407117f1b4Smrg#include "teximage.h" 417117f1b4Smrg#include "texobj.h" 427117f1b4Smrg#include "mtypes.h" 434a49301eSmrg#include "shader/prog_instruction.h" 444a49301eSmrg 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->CompareMode = GL_NONE; /* ARB_shadow */ 1367117f1b4Smrg obj->CompareFunc = GL_LEQUAL; /* ARB_shadow */ 1374a49301eSmrg obj->CompareFailValue = 0.0F; /* ARB_shadow_ambient */ 1387117f1b4Smrg obj->DepthMode = GL_LUMINANCE; /* ARB_depth_texture */ 1394a49301eSmrg obj->Swizzle[0] = GL_RED; 1404a49301eSmrg obj->Swizzle[1] = GL_GREEN; 1414a49301eSmrg obj->Swizzle[2] = GL_BLUE; 1424a49301eSmrg obj->Swizzle[3] = GL_ALPHA; 1434a49301eSmrg obj->_Swizzle = SWIZZLE_NOOP; 144c1f859d4Smrg} 145c1f859d4Smrg 146c1f859d4Smrg 147c1f859d4Smrg/** 148c1f859d4Smrg * Some texture initialization can't be finished until we know which 149c1f859d4Smrg * target it's getting bound to (GL_TEXTURE_1D/2D/etc). 150c1f859d4Smrg */ 151c1f859d4Smrgstatic void 152c1f859d4Smrgfinish_texture_init(GLcontext *ctx, GLenum target, 153c1f859d4Smrg struct gl_texture_object *obj) 154c1f859d4Smrg{ 155c1f859d4Smrg assert(obj->Target == 0); 156c1f859d4Smrg 157c1f859d4Smrg if (target == GL_TEXTURE_RECTANGLE_NV) { 158c1f859d4Smrg /* have to init wrap and filter state here - kind of klunky */ 159c1f859d4Smrg obj->WrapS = GL_CLAMP_TO_EDGE; 160c1f859d4Smrg obj->WrapT = GL_CLAMP_TO_EDGE; 161c1f859d4Smrg obj->WrapR = GL_CLAMP_TO_EDGE; 162c1f859d4Smrg obj->MinFilter = GL_LINEAR; 163c1f859d4Smrg if (ctx->Driver.TexParameter) { 164c1f859d4Smrg static const GLfloat fparam_wrap[1] = {(GLfloat) GL_CLAMP_TO_EDGE}; 165c1f859d4Smrg static const GLfloat fparam_filter[1] = {(GLfloat) GL_LINEAR}; 166c1f859d4Smrg ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_S, fparam_wrap); 167c1f859d4Smrg ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_T, fparam_wrap); 168c1f859d4Smrg ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_R, fparam_wrap); 169c1f859d4Smrg ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_MIN_FILTER, fparam_filter); 170c1f859d4Smrg } 171c1f859d4Smrg } 1727117f1b4Smrg} 1737117f1b4Smrg 1747117f1b4Smrg 1757117f1b4Smrg/** 1767117f1b4Smrg * Deallocate a texture object struct. It should have already been 1777117f1b4Smrg * removed from the texture object pool. 178c1f859d4Smrg * Called via ctx->Driver.DeleteTexture() if not overriden by a driver. 1797117f1b4Smrg * 1807117f1b4Smrg * \param shared the shared GL state to which the object belongs. 1814a49301eSmrg * \param texObj the texture object to delete. 1827117f1b4Smrg */ 1837117f1b4Smrgvoid 1847117f1b4Smrg_mesa_delete_texture_object( GLcontext *ctx, struct gl_texture_object *texObj ) 1857117f1b4Smrg{ 1867117f1b4Smrg GLuint i, face; 1877117f1b4Smrg 1887117f1b4Smrg (void) ctx; 1897117f1b4Smrg 1907117f1b4Smrg /* Set Target to an invalid value. With some assertions elsewhere 1917117f1b4Smrg * we can try to detect possible use of deleted textures. 1927117f1b4Smrg */ 1937117f1b4Smrg texObj->Target = 0x99; 1947117f1b4Smrg 1957117f1b4Smrg _mesa_free_colortable_data(&texObj->Palette); 1967117f1b4Smrg 1977117f1b4Smrg /* free the texture images */ 1987117f1b4Smrg for (face = 0; face < 6; face++) { 1997117f1b4Smrg for (i = 0; i < MAX_TEXTURE_LEVELS; i++) { 2007117f1b4Smrg if (texObj->Image[face][i]) { 2017117f1b4Smrg _mesa_delete_texture_image( ctx, texObj->Image[face][i] ); 2027117f1b4Smrg } 2037117f1b4Smrg } 2047117f1b4Smrg } 2057117f1b4Smrg 2067117f1b4Smrg /* destroy the mutex -- it may have allocated memory (eg on bsd) */ 2077117f1b4Smrg _glthread_DESTROY_MUTEX(texObj->Mutex); 2087117f1b4Smrg 2097117f1b4Smrg /* free this object */ 2107117f1b4Smrg _mesa_free(texObj); 2117117f1b4Smrg} 2127117f1b4Smrg 2137117f1b4Smrg 2147117f1b4Smrg 2157117f1b4Smrg 2167117f1b4Smrg/** 2177117f1b4Smrg * Copy texture object state from one texture object to another. 2187117f1b4Smrg * Use for glPush/PopAttrib. 2197117f1b4Smrg * 2207117f1b4Smrg * \param dest destination texture object. 2217117f1b4Smrg * \param src source texture object. 2227117f1b4Smrg */ 2237117f1b4Smrgvoid 2247117f1b4Smrg_mesa_copy_texture_object( struct gl_texture_object *dest, 2257117f1b4Smrg const struct gl_texture_object *src ) 2267117f1b4Smrg{ 2277117f1b4Smrg dest->Target = src->Target; 2287117f1b4Smrg dest->Name = src->Name; 2297117f1b4Smrg dest->Priority = src->Priority; 2307117f1b4Smrg dest->BorderColor[0] = src->BorderColor[0]; 2317117f1b4Smrg dest->BorderColor[1] = src->BorderColor[1]; 2327117f1b4Smrg dest->BorderColor[2] = src->BorderColor[2]; 2337117f1b4Smrg dest->BorderColor[3] = src->BorderColor[3]; 2347117f1b4Smrg dest->WrapS = src->WrapS; 2357117f1b4Smrg dest->WrapT = src->WrapT; 2367117f1b4Smrg dest->WrapR = src->WrapR; 2377117f1b4Smrg dest->MinFilter = src->MinFilter; 2387117f1b4Smrg dest->MagFilter = src->MagFilter; 2397117f1b4Smrg dest->MinLod = src->MinLod; 2407117f1b4Smrg dest->MaxLod = src->MaxLod; 2417117f1b4Smrg dest->LodBias = src->LodBias; 2427117f1b4Smrg dest->BaseLevel = src->BaseLevel; 2437117f1b4Smrg dest->MaxLevel = src->MaxLevel; 2447117f1b4Smrg dest->MaxAnisotropy = src->MaxAnisotropy; 2457117f1b4Smrg dest->CompareMode = src->CompareMode; 2467117f1b4Smrg dest->CompareFunc = src->CompareFunc; 2474a49301eSmrg dest->CompareFailValue = src->CompareFailValue; 2487117f1b4Smrg dest->DepthMode = src->DepthMode; 2497117f1b4Smrg dest->_MaxLevel = src->_MaxLevel; 2507117f1b4Smrg dest->_MaxLambda = src->_MaxLambda; 2517117f1b4Smrg dest->GenerateMipmap = src->GenerateMipmap; 2527117f1b4Smrg dest->Palette = src->Palette; 253c1f859d4Smrg dest->_Complete = src->_Complete; 2544a49301eSmrg COPY_4V(dest->Swizzle, src->Swizzle); 2554a49301eSmrg dest->_Swizzle = src->_Swizzle; 2564a49301eSmrg} 2574a49301eSmrg 2584a49301eSmrg 2594a49301eSmrg/** 2604a49301eSmrg * Clear all texture images of the given texture object. 2614a49301eSmrg * 2624a49301eSmrg * \param ctx GL context. 2634a49301eSmrg * \param t texture object. 2644a49301eSmrg * 2654a49301eSmrg * \sa _mesa_clear_texture_image(). 2664a49301eSmrg */ 2674a49301eSmrgvoid 2684a49301eSmrg_mesa_clear_texture_object(GLcontext *ctx, struct gl_texture_object *texObj) 2694a49301eSmrg{ 2704a49301eSmrg GLuint i, j; 2714a49301eSmrg 2724a49301eSmrg if (texObj->Target == 0) 2734a49301eSmrg return; 2744a49301eSmrg 2754a49301eSmrg for (i = 0; i < MAX_FACES; i++) { 2764a49301eSmrg for (j = 0; j < MAX_TEXTURE_LEVELS; j++) { 2774a49301eSmrg struct gl_texture_image *texImage = texObj->Image[i][j]; 2784a49301eSmrg if (texImage) 2794a49301eSmrg _mesa_clear_texture_image(ctx, texImage); 2804a49301eSmrg } 2814a49301eSmrg } 2827117f1b4Smrg} 2837117f1b4Smrg 2847117f1b4Smrg 2857117f1b4Smrg/** 2867117f1b4Smrg * Check if the given texture object is valid by examining its Target field. 2877117f1b4Smrg * For debugging only. 2887117f1b4Smrg */ 2897117f1b4Smrgstatic GLboolean 2907117f1b4Smrgvalid_texture_object(const struct gl_texture_object *tex) 2917117f1b4Smrg{ 2927117f1b4Smrg switch (tex->Target) { 2937117f1b4Smrg case 0: 2947117f1b4Smrg case GL_TEXTURE_1D: 2957117f1b4Smrg case GL_TEXTURE_2D: 2967117f1b4Smrg case GL_TEXTURE_3D: 2977117f1b4Smrg case GL_TEXTURE_CUBE_MAP_ARB: 2987117f1b4Smrg case GL_TEXTURE_RECTANGLE_NV: 299c1f859d4Smrg case GL_TEXTURE_1D_ARRAY_EXT: 300c1f859d4Smrg case GL_TEXTURE_2D_ARRAY_EXT: 3017117f1b4Smrg return GL_TRUE; 3027117f1b4Smrg case 0x99: 3037117f1b4Smrg _mesa_problem(NULL, "invalid reference to a deleted texture object"); 3047117f1b4Smrg return GL_FALSE; 3057117f1b4Smrg default: 3064a49301eSmrg _mesa_problem(NULL, "invalid texture object Target 0x%x, Id = %u", 3074a49301eSmrg tex->Target, tex->Name); 3087117f1b4Smrg return GL_FALSE; 3097117f1b4Smrg } 3107117f1b4Smrg} 3117117f1b4Smrg 3127117f1b4Smrg 3137117f1b4Smrg/** 3147117f1b4Smrg * Reference (or unreference) a texture object. 3157117f1b4Smrg * If '*ptr', decrement *ptr's refcount (and delete if it becomes zero). 3167117f1b4Smrg * If 'tex' is non-null, increment its refcount. 3177117f1b4Smrg */ 3187117f1b4Smrgvoid 3197117f1b4Smrg_mesa_reference_texobj(struct gl_texture_object **ptr, 3207117f1b4Smrg struct gl_texture_object *tex) 3217117f1b4Smrg{ 3227117f1b4Smrg assert(ptr); 3237117f1b4Smrg if (*ptr == tex) { 3247117f1b4Smrg /* no change */ 3257117f1b4Smrg return; 3267117f1b4Smrg } 3277117f1b4Smrg 3287117f1b4Smrg if (*ptr) { 3297117f1b4Smrg /* Unreference the old texture */ 3307117f1b4Smrg GLboolean deleteFlag = GL_FALSE; 3317117f1b4Smrg struct gl_texture_object *oldTex = *ptr; 3327117f1b4Smrg 3334a49301eSmrg ASSERT(valid_texture_object(oldTex)); 3347117f1b4Smrg 3357117f1b4Smrg _glthread_LOCK_MUTEX(oldTex->Mutex); 3367117f1b4Smrg ASSERT(oldTex->RefCount > 0); 3377117f1b4Smrg oldTex->RefCount--; 3387117f1b4Smrg 3397117f1b4Smrg deleteFlag = (oldTex->RefCount == 0); 3407117f1b4Smrg _glthread_UNLOCK_MUTEX(oldTex->Mutex); 3417117f1b4Smrg 3427117f1b4Smrg if (deleteFlag) { 3437117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 3447117f1b4Smrg if (ctx) 3457117f1b4Smrg ctx->Driver.DeleteTexture(ctx, oldTex); 3467117f1b4Smrg else 3477117f1b4Smrg _mesa_problem(NULL, "Unable to delete texture, no context"); 3487117f1b4Smrg } 3497117f1b4Smrg 3507117f1b4Smrg *ptr = NULL; 3517117f1b4Smrg } 3527117f1b4Smrg assert(!*ptr); 3537117f1b4Smrg 3547117f1b4Smrg if (tex) { 3557117f1b4Smrg /* reference new texture */ 3564a49301eSmrg ASSERT(valid_texture_object(tex)); 3577117f1b4Smrg _glthread_LOCK_MUTEX(tex->Mutex); 3587117f1b4Smrg if (tex->RefCount == 0) { 3597117f1b4Smrg /* this texture's being deleted (look just above) */ 3607117f1b4Smrg /* Not sure this can every really happen. Warn if it does. */ 3617117f1b4Smrg _mesa_problem(NULL, "referencing deleted texture object"); 3627117f1b4Smrg *ptr = NULL; 3637117f1b4Smrg } 3647117f1b4Smrg else { 3657117f1b4Smrg tex->RefCount++; 3667117f1b4Smrg *ptr = tex; 3677117f1b4Smrg } 3687117f1b4Smrg _glthread_UNLOCK_MUTEX(tex->Mutex); 3697117f1b4Smrg } 3707117f1b4Smrg} 3717117f1b4Smrg 3727117f1b4Smrg 3737117f1b4Smrg 3747117f1b4Smrg/** 3757117f1b4Smrg * Report why a texture object is incomplete. 3767117f1b4Smrg * 3777117f1b4Smrg * \param t texture object. 3787117f1b4Smrg * \param why string describing why it's incomplete. 3797117f1b4Smrg * 3807117f1b4Smrg * \note For debug purposes only. 3817117f1b4Smrg */ 3827117f1b4Smrg#if 0 3837117f1b4Smrgstatic void 3847117f1b4Smrgincomplete(const struct gl_texture_object *t, const char *why) 3857117f1b4Smrg{ 3867117f1b4Smrg _mesa_printf("Texture Obj %d incomplete because: %s\n", t->Name, why); 3877117f1b4Smrg} 3887117f1b4Smrg#else 3897117f1b4Smrg#define incomplete(t, why) 3907117f1b4Smrg#endif 3917117f1b4Smrg 3927117f1b4Smrg 3937117f1b4Smrg/** 3947117f1b4Smrg * Examine a texture object to determine if it is complete. 3957117f1b4Smrg * 3967117f1b4Smrg * The gl_texture_object::Complete flag will be set to GL_TRUE or GL_FALSE 3977117f1b4Smrg * accordingly. 3987117f1b4Smrg * 3997117f1b4Smrg * \param ctx GL context. 4007117f1b4Smrg * \param t texture object. 4017117f1b4Smrg * 4027117f1b4Smrg * According to the texture target, verifies that each of the mipmaps is 4037117f1b4Smrg * present and has the expected size. 4047117f1b4Smrg */ 4057117f1b4Smrgvoid 4067117f1b4Smrg_mesa_test_texobj_completeness( const GLcontext *ctx, 4077117f1b4Smrg struct gl_texture_object *t ) 4087117f1b4Smrg{ 4097117f1b4Smrg const GLint baseLevel = t->BaseLevel; 4107117f1b4Smrg GLint maxLog2 = 0, maxLevels = 0; 4117117f1b4Smrg 412c1f859d4Smrg t->_Complete = GL_TRUE; /* be optimistic */ 413c1f859d4Smrg 414c1f859d4Smrg /* Detect cases where the application set the base level to an invalid 415c1f859d4Smrg * value. 416c1f859d4Smrg */ 4174a49301eSmrg if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS)) { 418c1f859d4Smrg char s[100]; 4194a49301eSmrg _mesa_sprintf(s, "base level = %d is invalid", baseLevel); 420c1f859d4Smrg incomplete(t, s); 421c1f859d4Smrg t->_Complete = GL_FALSE; 422c1f859d4Smrg return; 423c1f859d4Smrg } 4247117f1b4Smrg 4257117f1b4Smrg /* Always need the base level image */ 4267117f1b4Smrg if (!t->Image[0][baseLevel]) { 4277117f1b4Smrg char s[100]; 4284a49301eSmrg _mesa_sprintf(s, "Image[baseLevel=%d] == NULL", baseLevel); 4297117f1b4Smrg incomplete(t, s); 430c1f859d4Smrg t->_Complete = GL_FALSE; 4317117f1b4Smrg return; 4327117f1b4Smrg } 4337117f1b4Smrg 4347117f1b4Smrg /* Check width/height/depth for zero */ 4357117f1b4Smrg if (t->Image[0][baseLevel]->Width == 0 || 4367117f1b4Smrg t->Image[0][baseLevel]->Height == 0 || 4377117f1b4Smrg t->Image[0][baseLevel]->Depth == 0) { 4387117f1b4Smrg incomplete(t, "texture width = 0"); 439c1f859d4Smrg t->_Complete = GL_FALSE; 4407117f1b4Smrg return; 4417117f1b4Smrg } 4427117f1b4Smrg 4437117f1b4Smrg /* Compute _MaxLevel */ 444c1f859d4Smrg if ((t->Target == GL_TEXTURE_1D) || 445c1f859d4Smrg (t->Target == GL_TEXTURE_1D_ARRAY_EXT)) { 4467117f1b4Smrg maxLog2 = t->Image[0][baseLevel]->WidthLog2; 4477117f1b4Smrg maxLevels = ctx->Const.MaxTextureLevels; 4487117f1b4Smrg } 449c1f859d4Smrg else if ((t->Target == GL_TEXTURE_2D) || 450c1f859d4Smrg (t->Target == GL_TEXTURE_2D_ARRAY_EXT)) { 4517117f1b4Smrg maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2, 4527117f1b4Smrg t->Image[0][baseLevel]->HeightLog2); 4537117f1b4Smrg maxLevels = ctx->Const.MaxTextureLevels; 4547117f1b4Smrg } 4557117f1b4Smrg else if (t->Target == GL_TEXTURE_3D) { 4567117f1b4Smrg GLint max = MAX2(t->Image[0][baseLevel]->WidthLog2, 4577117f1b4Smrg t->Image[0][baseLevel]->HeightLog2); 4587117f1b4Smrg maxLog2 = MAX2(max, (GLint)(t->Image[0][baseLevel]->DepthLog2)); 4597117f1b4Smrg maxLevels = ctx->Const.Max3DTextureLevels; 4607117f1b4Smrg } 4617117f1b4Smrg else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) { 4627117f1b4Smrg maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2, 4637117f1b4Smrg t->Image[0][baseLevel]->HeightLog2); 4647117f1b4Smrg maxLevels = ctx->Const.MaxCubeTextureLevels; 4657117f1b4Smrg } 4667117f1b4Smrg else if (t->Target == GL_TEXTURE_RECTANGLE_NV) { 4677117f1b4Smrg maxLog2 = 0; /* not applicable */ 4687117f1b4Smrg maxLevels = 1; /* no mipmapping */ 4697117f1b4Smrg } 4707117f1b4Smrg else { 4717117f1b4Smrg _mesa_problem(ctx, "Bad t->Target in _mesa_test_texobj_completeness"); 4727117f1b4Smrg return; 4737117f1b4Smrg } 4747117f1b4Smrg 4757117f1b4Smrg ASSERT(maxLevels > 0); 4767117f1b4Smrg 4777117f1b4Smrg t->_MaxLevel = baseLevel + maxLog2; 4787117f1b4Smrg t->_MaxLevel = MIN2(t->_MaxLevel, t->MaxLevel); 4797117f1b4Smrg t->_MaxLevel = MIN2(t->_MaxLevel, maxLevels - 1); 4807117f1b4Smrg 4817117f1b4Smrg /* Compute _MaxLambda = q - b (see the 1.2 spec) used during mipmapping */ 4827117f1b4Smrg t->_MaxLambda = (GLfloat) (t->_MaxLevel - t->BaseLevel); 4837117f1b4Smrg 4847117f1b4Smrg if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) { 4857117f1b4Smrg /* make sure that all six cube map level 0 images are the same size */ 4867117f1b4Smrg const GLuint w = t->Image[0][baseLevel]->Width2; 4877117f1b4Smrg const GLuint h = t->Image[0][baseLevel]->Height2; 4887117f1b4Smrg GLuint face; 4897117f1b4Smrg for (face = 1; face < 6; face++) { 4907117f1b4Smrg if (t->Image[face][baseLevel] == NULL || 4917117f1b4Smrg t->Image[face][baseLevel]->Width2 != w || 4927117f1b4Smrg t->Image[face][baseLevel]->Height2 != h) { 493c1f859d4Smrg t->_Complete = GL_FALSE; 4944a49301eSmrg incomplete(t, "Cube face missing or mismatched size"); 4957117f1b4Smrg return; 4967117f1b4Smrg } 4977117f1b4Smrg } 4987117f1b4Smrg } 4997117f1b4Smrg 5007117f1b4Smrg /* extra checking for mipmaps */ 5017117f1b4Smrg if (t->MinFilter != GL_NEAREST && t->MinFilter != GL_LINEAR) { 5027117f1b4Smrg /* 5037117f1b4Smrg * Mipmapping: determine if we have a complete set of mipmaps 5047117f1b4Smrg */ 5057117f1b4Smrg GLint i; 5067117f1b4Smrg GLint minLevel = baseLevel; 5077117f1b4Smrg GLint maxLevel = t->_MaxLevel; 5087117f1b4Smrg 5097117f1b4Smrg if (minLevel > maxLevel) { 510c1f859d4Smrg t->_Complete = GL_FALSE; 5117117f1b4Smrg incomplete(t, "minLevel > maxLevel"); 5127117f1b4Smrg return; 5137117f1b4Smrg } 5147117f1b4Smrg 5157117f1b4Smrg /* Test dimension-independent attributes */ 5167117f1b4Smrg for (i = minLevel; i <= maxLevel; i++) { 5177117f1b4Smrg if (t->Image[0][i]) { 5187117f1b4Smrg if (t->Image[0][i]->TexFormat != t->Image[0][baseLevel]->TexFormat) { 519c1f859d4Smrg t->_Complete = GL_FALSE; 5207117f1b4Smrg incomplete(t, "Format[i] != Format[baseLevel]"); 5217117f1b4Smrg return; 5227117f1b4Smrg } 5237117f1b4Smrg if (t->Image[0][i]->Border != t->Image[0][baseLevel]->Border) { 524c1f859d4Smrg t->_Complete = GL_FALSE; 5257117f1b4Smrg incomplete(t, "Border[i] != Border[baseLevel]"); 5267117f1b4Smrg return; 5277117f1b4Smrg } 5287117f1b4Smrg } 5297117f1b4Smrg } 5307117f1b4Smrg 5317117f1b4Smrg /* Test things which depend on number of texture image dimensions */ 532c1f859d4Smrg if ((t->Target == GL_TEXTURE_1D) || 533c1f859d4Smrg (t->Target == GL_TEXTURE_1D_ARRAY_EXT)) { 5347117f1b4Smrg /* Test 1-D mipmaps */ 5357117f1b4Smrg GLuint width = t->Image[0][baseLevel]->Width2; 5367117f1b4Smrg for (i = baseLevel + 1; i < maxLevels; i++) { 5377117f1b4Smrg if (width > 1) { 5387117f1b4Smrg width /= 2; 5397117f1b4Smrg } 5407117f1b4Smrg if (i >= minLevel && i <= maxLevel) { 5417117f1b4Smrg if (!t->Image[0][i]) { 542c1f859d4Smrg t->_Complete = GL_FALSE; 5437117f1b4Smrg incomplete(t, "1D Image[0][i] == NULL"); 5447117f1b4Smrg return; 5457117f1b4Smrg } 5467117f1b4Smrg if (t->Image[0][i]->Width2 != width ) { 547c1f859d4Smrg t->_Complete = GL_FALSE; 5487117f1b4Smrg incomplete(t, "1D Image[0][i] bad width"); 5497117f1b4Smrg return; 5507117f1b4Smrg } 5517117f1b4Smrg } 5527117f1b4Smrg if (width == 1) { 5537117f1b4Smrg return; /* found smallest needed mipmap, all done! */ 5547117f1b4Smrg } 5557117f1b4Smrg } 5567117f1b4Smrg } 557c1f859d4Smrg else if ((t->Target == GL_TEXTURE_2D) || 558c1f859d4Smrg (t->Target == GL_TEXTURE_2D_ARRAY_EXT)) { 5597117f1b4Smrg /* Test 2-D mipmaps */ 5607117f1b4Smrg GLuint width = t->Image[0][baseLevel]->Width2; 5617117f1b4Smrg GLuint height = t->Image[0][baseLevel]->Height2; 5627117f1b4Smrg for (i = baseLevel + 1; i < maxLevels; i++) { 5637117f1b4Smrg if (width > 1) { 5647117f1b4Smrg width /= 2; 5657117f1b4Smrg } 5667117f1b4Smrg if (height > 1) { 5677117f1b4Smrg height /= 2; 5687117f1b4Smrg } 5697117f1b4Smrg if (i >= minLevel && i <= maxLevel) { 5707117f1b4Smrg if (!t->Image[0][i]) { 571c1f859d4Smrg t->_Complete = GL_FALSE; 5727117f1b4Smrg incomplete(t, "2D Image[0][i] == NULL"); 5737117f1b4Smrg return; 5747117f1b4Smrg } 5757117f1b4Smrg if (t->Image[0][i]->Width2 != width) { 576c1f859d4Smrg t->_Complete = GL_FALSE; 5777117f1b4Smrg incomplete(t, "2D Image[0][i] bad width"); 5787117f1b4Smrg return; 5797117f1b4Smrg } 5807117f1b4Smrg if (t->Image[0][i]->Height2 != height) { 581c1f859d4Smrg t->_Complete = GL_FALSE; 5827117f1b4Smrg incomplete(t, "2D Image[0][i] bad height"); 5837117f1b4Smrg return; 5847117f1b4Smrg } 5857117f1b4Smrg if (width==1 && height==1) { 5867117f1b4Smrg return; /* found smallest needed mipmap, all done! */ 5877117f1b4Smrg } 5887117f1b4Smrg } 5897117f1b4Smrg } 5907117f1b4Smrg } 5917117f1b4Smrg else if (t->Target == GL_TEXTURE_3D) { 5927117f1b4Smrg /* Test 3-D mipmaps */ 5937117f1b4Smrg GLuint width = t->Image[0][baseLevel]->Width2; 5947117f1b4Smrg GLuint height = t->Image[0][baseLevel]->Height2; 5957117f1b4Smrg GLuint depth = t->Image[0][baseLevel]->Depth2; 5967117f1b4Smrg for (i = baseLevel + 1; i < maxLevels; i++) { 5977117f1b4Smrg if (width > 1) { 5987117f1b4Smrg width /= 2; 5997117f1b4Smrg } 6007117f1b4Smrg if (height > 1) { 6017117f1b4Smrg height /= 2; 6027117f1b4Smrg } 6037117f1b4Smrg if (depth > 1) { 6047117f1b4Smrg depth /= 2; 6057117f1b4Smrg } 6067117f1b4Smrg if (i >= minLevel && i <= maxLevel) { 6077117f1b4Smrg if (!t->Image[0][i]) { 6087117f1b4Smrg incomplete(t, "3D Image[0][i] == NULL"); 609c1f859d4Smrg t->_Complete = GL_FALSE; 6107117f1b4Smrg return; 6117117f1b4Smrg } 6127117f1b4Smrg if (t->Image[0][i]->_BaseFormat == GL_DEPTH_COMPONENT) { 613c1f859d4Smrg t->_Complete = GL_FALSE; 6147117f1b4Smrg incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex"); 6157117f1b4Smrg return; 6167117f1b4Smrg } 6177117f1b4Smrg if (t->Image[0][i]->Width2 != width) { 618c1f859d4Smrg t->_Complete = GL_FALSE; 6197117f1b4Smrg incomplete(t, "3D Image[0][i] bad width"); 6207117f1b4Smrg return; 6217117f1b4Smrg } 6227117f1b4Smrg if (t->Image[0][i]->Height2 != height) { 623c1f859d4Smrg t->_Complete = GL_FALSE; 6247117f1b4Smrg incomplete(t, "3D Image[0][i] bad height"); 6257117f1b4Smrg return; 6267117f1b4Smrg } 6277117f1b4Smrg if (t->Image[0][i]->Depth2 != depth) { 628c1f859d4Smrg t->_Complete = GL_FALSE; 6297117f1b4Smrg incomplete(t, "3D Image[0][i] bad depth"); 6307117f1b4Smrg return; 6317117f1b4Smrg } 6327117f1b4Smrg } 6337117f1b4Smrg if (width == 1 && height == 1 && depth == 1) { 6347117f1b4Smrg return; /* found smallest needed mipmap, all done! */ 6357117f1b4Smrg } 6367117f1b4Smrg } 6377117f1b4Smrg } 6387117f1b4Smrg else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) { 6397117f1b4Smrg /* make sure 6 cube faces are consistant */ 6407117f1b4Smrg GLuint width = t->Image[0][baseLevel]->Width2; 6417117f1b4Smrg GLuint height = t->Image[0][baseLevel]->Height2; 6427117f1b4Smrg for (i = baseLevel + 1; i < maxLevels; i++) { 6437117f1b4Smrg if (width > 1) { 6447117f1b4Smrg width /= 2; 6457117f1b4Smrg } 6467117f1b4Smrg if (height > 1) { 6477117f1b4Smrg height /= 2; 6487117f1b4Smrg } 6497117f1b4Smrg if (i >= minLevel && i <= maxLevel) { 6507117f1b4Smrg GLuint face; 6517117f1b4Smrg for (face = 0; face < 6; face++) { 6527117f1b4Smrg /* check that we have images defined */ 6537117f1b4Smrg if (!t->Image[face][i]) { 654c1f859d4Smrg t->_Complete = GL_FALSE; 6557117f1b4Smrg incomplete(t, "CubeMap Image[n][i] == NULL"); 6567117f1b4Smrg return; 6577117f1b4Smrg } 6587117f1b4Smrg /* Don't support GL_DEPTH_COMPONENT for cube maps */ 6597117f1b4Smrg if (t->Image[face][i]->_BaseFormat == GL_DEPTH_COMPONENT) { 660c1f859d4Smrg t->_Complete = GL_FALSE; 6617117f1b4Smrg incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex"); 6627117f1b4Smrg return; 6637117f1b4Smrg } 6647117f1b4Smrg /* check that all six images have same size */ 6657117f1b4Smrg if (t->Image[face][i]->Width2!=width || 6667117f1b4Smrg t->Image[face][i]->Height2!=height) { 667c1f859d4Smrg t->_Complete = GL_FALSE; 6687117f1b4Smrg incomplete(t, "CubeMap Image[n][i] bad size"); 6697117f1b4Smrg return; 6707117f1b4Smrg } 6717117f1b4Smrg } 6727117f1b4Smrg } 6737117f1b4Smrg if (width == 1 && height == 1) { 6747117f1b4Smrg return; /* found smallest needed mipmap, all done! */ 6757117f1b4Smrg } 6767117f1b4Smrg } 6777117f1b4Smrg } 6787117f1b4Smrg else if (t->Target == GL_TEXTURE_RECTANGLE_NV) { 6797117f1b4Smrg /* XXX special checking? */ 6807117f1b4Smrg } 6817117f1b4Smrg else { 6827117f1b4Smrg /* Target = ??? */ 6837117f1b4Smrg _mesa_problem(ctx, "Bug in gl_test_texture_object_completeness\n"); 6847117f1b4Smrg } 6857117f1b4Smrg } 6867117f1b4Smrg} 6877117f1b4Smrg 6884a49301eSmrg 6894a49301eSmrg/** 6904a49301eSmrg * Mark a texture object dirty. It forces the object to be incomplete 6914a49301eSmrg * and optionally forces the context to re-validate its state. 6924a49301eSmrg * 6934a49301eSmrg * \param ctx GL context. 6944a49301eSmrg * \param texObj texture object. 6954a49301eSmrg * \param invalidate_state also invalidate context state. 6964a49301eSmrg */ 6974a49301eSmrgvoid 6984a49301eSmrg_mesa_dirty_texobj(GLcontext *ctx, struct gl_texture_object *texObj, 6994a49301eSmrg GLboolean invalidate_state) 7004a49301eSmrg{ 7014a49301eSmrg texObj->_Complete = GL_FALSE; 7024a49301eSmrg if (invalidate_state) 7034a49301eSmrg ctx->NewState |= _NEW_TEXTURE; 7044a49301eSmrg} 7054a49301eSmrg 7064a49301eSmrg 7074a49301eSmrg/** 7084a49301eSmrg * Return pointer to a default/fallback texture. 7094a49301eSmrg * The texture is a 2D 8x8 RGBA texture with all texels = (0,0,0,1). 7104a49301eSmrg * That's the value a sampler should get when sampling from an 7114a49301eSmrg * incomplete texture. 7124a49301eSmrg */ 7134a49301eSmrgstruct gl_texture_object * 7144a49301eSmrg_mesa_get_fallback_texture(GLcontext *ctx) 7154a49301eSmrg{ 7164a49301eSmrg if (!ctx->Shared->FallbackTex) { 7174a49301eSmrg /* create fallback texture now */ 7184a49301eSmrg static GLubyte texels[8 * 8][4]; 7194a49301eSmrg struct gl_texture_object *texObj; 7204a49301eSmrg struct gl_texture_image *texImage; 7214a49301eSmrg GLuint i; 7224a49301eSmrg 7234a49301eSmrg for (i = 0; i < 8 * 8; i++) { 7244a49301eSmrg texels[i][0] = 7254a49301eSmrg texels[i][1] = 7264a49301eSmrg texels[i][2] = 0x0; 7274a49301eSmrg texels[i][3] = 0xff; 7284a49301eSmrg } 7294a49301eSmrg 7304a49301eSmrg /* create texture object */ 7314a49301eSmrg texObj = ctx->Driver.NewTextureObject(ctx, 0, GL_TEXTURE_2D); 7324a49301eSmrg assert(texObj->RefCount == 1); 7334a49301eSmrg texObj->MinFilter = GL_NEAREST; 7344a49301eSmrg texObj->MagFilter = GL_NEAREST; 7354a49301eSmrg 7364a49301eSmrg /* create level[0] texture image */ 7374a49301eSmrg texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, 0); 7384a49301eSmrg 7394a49301eSmrg /* init the image fields */ 7404a49301eSmrg _mesa_init_teximage_fields(ctx, GL_TEXTURE_2D, texImage, 7414a49301eSmrg 8, 8, 1, 0, GL_RGBA); 7424a49301eSmrg 7434a49301eSmrg texImage->TexFormat = 7444a49301eSmrg ctx->Driver.ChooseTextureFormat(ctx, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE); 7454a49301eSmrg ASSERT(texImage->TexFormat != MESA_FORMAT_NONE); 7464a49301eSmrg 7474a49301eSmrg /* set image data */ 7484a49301eSmrg ctx->Driver.TexImage2D(ctx, GL_TEXTURE_2D, 0, GL_RGBA, 7494a49301eSmrg 8, 8, 0, 7504a49301eSmrg GL_RGBA, GL_UNSIGNED_BYTE, texels, 7514a49301eSmrg &ctx->DefaultPacking, texObj, texImage); 7524a49301eSmrg 7534a49301eSmrg _mesa_test_texobj_completeness(ctx, texObj); 7544a49301eSmrg assert(texObj->_Complete); 7554a49301eSmrg 7564a49301eSmrg ctx->Shared->FallbackTex = texObj; 7574a49301eSmrg } 7584a49301eSmrg return ctx->Shared->FallbackTex; 7594a49301eSmrg} 7604a49301eSmrg 7614a49301eSmrg 7627117f1b4Smrg/*@}*/ 7637117f1b4Smrg 7647117f1b4Smrg 7657117f1b4Smrg/***********************************************************************/ 7667117f1b4Smrg/** \name API functions */ 7677117f1b4Smrg/*@{*/ 7687117f1b4Smrg 7697117f1b4Smrg 7707117f1b4Smrg/** 7717117f1b4Smrg * Generate texture names. 7727117f1b4Smrg * 7737117f1b4Smrg * \param n number of texture names to be generated. 7747117f1b4Smrg * \param textures an array in which will hold the generated texture names. 7757117f1b4Smrg * 7767117f1b4Smrg * \sa glGenTextures(). 7777117f1b4Smrg * 778c1f859d4Smrg * Calls _mesa_HashFindFreeKeyBlock() to find a block of free texture 779c1f859d4Smrg * IDs which are stored in \p textures. Corresponding empty texture 780c1f859d4Smrg * objects are also generated. 7817117f1b4Smrg */ 7827117f1b4Smrgvoid GLAPIENTRY 7837117f1b4Smrg_mesa_GenTextures( GLsizei n, GLuint *textures ) 7847117f1b4Smrg{ 7857117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 7867117f1b4Smrg GLuint first; 7877117f1b4Smrg GLint i; 7887117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 7897117f1b4Smrg 7907117f1b4Smrg if (n < 0) { 7917117f1b4Smrg _mesa_error( ctx, GL_INVALID_VALUE, "glGenTextures" ); 7927117f1b4Smrg return; 7937117f1b4Smrg } 7947117f1b4Smrg 7957117f1b4Smrg if (!textures) 7967117f1b4Smrg return; 7977117f1b4Smrg 7987117f1b4Smrg /* 7997117f1b4Smrg * This must be atomic (generation and allocation of texture IDs) 8007117f1b4Smrg */ 801c1f859d4Smrg _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 8027117f1b4Smrg 8037117f1b4Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Shared->TexObjects, n); 8047117f1b4Smrg 8057117f1b4Smrg /* Allocate new, empty texture objects */ 8067117f1b4Smrg for (i = 0; i < n; i++) { 8077117f1b4Smrg struct gl_texture_object *texObj; 8087117f1b4Smrg GLuint name = first + i; 8097117f1b4Smrg GLenum target = 0; 8107117f1b4Smrg texObj = (*ctx->Driver.NewTextureObject)( ctx, name, target); 8117117f1b4Smrg if (!texObj) { 812c1f859d4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 8137117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures"); 8147117f1b4Smrg return; 8157117f1b4Smrg } 8167117f1b4Smrg 8177117f1b4Smrg /* insert into hash table */ 8187117f1b4Smrg _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj); 8197117f1b4Smrg 8207117f1b4Smrg textures[i] = name; 8217117f1b4Smrg } 8227117f1b4Smrg 823c1f859d4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 8247117f1b4Smrg} 8257117f1b4Smrg 8267117f1b4Smrg 8277117f1b4Smrg/** 8287117f1b4Smrg * Check if the given texture object is bound to the current draw or 8297117f1b4Smrg * read framebuffer. If so, Unbind it. 8307117f1b4Smrg */ 8317117f1b4Smrgstatic void 8327117f1b4Smrgunbind_texobj_from_fbo(GLcontext *ctx, struct gl_texture_object *texObj) 8337117f1b4Smrg{ 8347117f1b4Smrg const GLuint n = (ctx->DrawBuffer == ctx->ReadBuffer) ? 1 : 2; 8357117f1b4Smrg GLuint i; 8367117f1b4Smrg 8377117f1b4Smrg for (i = 0; i < n; i++) { 8387117f1b4Smrg struct gl_framebuffer *fb = (i == 0) ? ctx->DrawBuffer : ctx->ReadBuffer; 8397117f1b4Smrg if (fb->Name) { 8407117f1b4Smrg GLuint j; 8417117f1b4Smrg for (j = 0; j < BUFFER_COUNT; j++) { 8427117f1b4Smrg if (fb->Attachment[j].Type == GL_TEXTURE && 8437117f1b4Smrg fb->Attachment[j].Texture == texObj) { 8447117f1b4Smrg _mesa_remove_attachment(ctx, fb->Attachment + j); 8457117f1b4Smrg } 8467117f1b4Smrg } 8477117f1b4Smrg } 8487117f1b4Smrg } 8497117f1b4Smrg} 8507117f1b4Smrg 8517117f1b4Smrg 8527117f1b4Smrg/** 8537117f1b4Smrg * Check if the given texture object is bound to any texture image units and 8547117f1b4Smrg * unbind it if so (revert to default textures). 8557117f1b4Smrg */ 8567117f1b4Smrgstatic void 8577117f1b4Smrgunbind_texobj_from_texunits(GLcontext *ctx, struct gl_texture_object *texObj) 8587117f1b4Smrg{ 859c1f859d4Smrg GLuint u, tex; 8607117f1b4Smrg 8617117f1b4Smrg for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) { 8627117f1b4Smrg struct gl_texture_unit *unit = &ctx->Texture.Unit[u]; 863c1f859d4Smrg for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { 864c1f859d4Smrg if (texObj == unit->CurrentTex[tex]) { 865c1f859d4Smrg _mesa_reference_texobj(&unit->CurrentTex[tex], 8664a49301eSmrg ctx->Shared->DefaultTex[tex]); 867c1f859d4Smrg ASSERT(unit->CurrentTex[tex]); 868c1f859d4Smrg break; 869c1f859d4Smrg } 8707117f1b4Smrg } 8717117f1b4Smrg } 8727117f1b4Smrg} 8737117f1b4Smrg 8747117f1b4Smrg 8757117f1b4Smrg/** 8767117f1b4Smrg * Delete named textures. 8777117f1b4Smrg * 8787117f1b4Smrg * \param n number of textures to be deleted. 8797117f1b4Smrg * \param textures array of texture IDs to be deleted. 8807117f1b4Smrg * 8817117f1b4Smrg * \sa glDeleteTextures(). 8827117f1b4Smrg * 8837117f1b4Smrg * If we're about to delete a texture that's currently bound to any 8847117f1b4Smrg * texture unit, unbind the texture first. Decrement the reference 8857117f1b4Smrg * count on the texture object and delete it if it's zero. 8867117f1b4Smrg * Recall that texture objects can be shared among several rendering 8877117f1b4Smrg * contexts. 8887117f1b4Smrg */ 8897117f1b4Smrgvoid GLAPIENTRY 8907117f1b4Smrg_mesa_DeleteTextures( GLsizei n, const GLuint *textures) 8917117f1b4Smrg{ 8927117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 8937117f1b4Smrg GLint i; 8947117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */ 8957117f1b4Smrg 8967117f1b4Smrg if (!textures) 8977117f1b4Smrg return; 8987117f1b4Smrg 8997117f1b4Smrg for (i = 0; i < n; i++) { 9007117f1b4Smrg if (textures[i] > 0) { 9017117f1b4Smrg struct gl_texture_object *delObj 9027117f1b4Smrg = _mesa_lookup_texture(ctx, textures[i]); 9037117f1b4Smrg 9047117f1b4Smrg if (delObj) { 9057117f1b4Smrg _mesa_lock_texture(ctx, delObj); 9067117f1b4Smrg 9077117f1b4Smrg /* Check if texture is bound to any framebuffer objects. 9087117f1b4Smrg * If so, unbind. 9097117f1b4Smrg * See section 4.4.2.3 of GL_EXT_framebuffer_object. 9107117f1b4Smrg */ 9117117f1b4Smrg unbind_texobj_from_fbo(ctx, delObj); 9127117f1b4Smrg 9137117f1b4Smrg /* Check if this texture is currently bound to any texture units. 9147117f1b4Smrg * If so, unbind it. 9157117f1b4Smrg */ 9167117f1b4Smrg unbind_texobj_from_texunits(ctx, delObj); 9177117f1b4Smrg 9187117f1b4Smrg _mesa_unlock_texture(ctx, delObj); 9197117f1b4Smrg 9207117f1b4Smrg ctx->NewState |= _NEW_TEXTURE; 9217117f1b4Smrg 9227117f1b4Smrg /* The texture _name_ is now free for re-use. 9237117f1b4Smrg * Remove it from the hash table now. 9247117f1b4Smrg */ 9257117f1b4Smrg _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 9267117f1b4Smrg _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name); 9277117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 9287117f1b4Smrg 9297117f1b4Smrg /* Unreference the texobj. If refcount hits zero, the texture 9307117f1b4Smrg * will be deleted. 9317117f1b4Smrg */ 9327117f1b4Smrg _mesa_reference_texobj(&delObj, NULL); 9337117f1b4Smrg } 9347117f1b4Smrg } 9357117f1b4Smrg } 9367117f1b4Smrg} 9377117f1b4Smrg 9387117f1b4Smrg 939c1f859d4Smrg/** 940c1f859d4Smrg * Convert a GL texture target enum such as GL_TEXTURE_2D or GL_TEXTURE_3D 941c1f859d4Smrg * into the corresponding Mesa texture target index. 942c1f859d4Smrg * Return -1 if target is invalid. 943c1f859d4Smrg */ 944c1f859d4Smrgstatic GLint 945c1f859d4Smrgtarget_enum_to_index(GLenum target) 946c1f859d4Smrg{ 947c1f859d4Smrg switch (target) { 948c1f859d4Smrg case GL_TEXTURE_1D: 949c1f859d4Smrg return TEXTURE_1D_INDEX; 950c1f859d4Smrg case GL_TEXTURE_2D: 951c1f859d4Smrg return TEXTURE_2D_INDEX; 952c1f859d4Smrg case GL_TEXTURE_3D: 953c1f859d4Smrg return TEXTURE_3D_INDEX; 954c1f859d4Smrg case GL_TEXTURE_CUBE_MAP_ARB: 955c1f859d4Smrg return TEXTURE_CUBE_INDEX; 956c1f859d4Smrg case GL_TEXTURE_RECTANGLE_NV: 957c1f859d4Smrg return TEXTURE_RECT_INDEX; 958c1f859d4Smrg case GL_TEXTURE_1D_ARRAY_EXT: 959c1f859d4Smrg return TEXTURE_1D_ARRAY_INDEX; 960c1f859d4Smrg case GL_TEXTURE_2D_ARRAY_EXT: 961c1f859d4Smrg return TEXTURE_2D_ARRAY_INDEX; 962c1f859d4Smrg default: 963c1f859d4Smrg return -1; 964c1f859d4Smrg } 965c1f859d4Smrg} 966c1f859d4Smrg 967c1f859d4Smrg 9687117f1b4Smrg/** 9697117f1b4Smrg * Bind a named texture to a texturing target. 9707117f1b4Smrg * 9717117f1b4Smrg * \param target texture target. 9727117f1b4Smrg * \param texName texture name. 9737117f1b4Smrg * 9747117f1b4Smrg * \sa glBindTexture(). 9757117f1b4Smrg * 9767117f1b4Smrg * Determines the old texture object bound and returns immediately if rebinding 9777117f1b4Smrg * the same texture. Get the current texture which is either a default texture 9787117f1b4Smrg * if name is null, a named texture from the hash, or a new texture if the 9797117f1b4Smrg * given texture name is new. Increments its reference count, binds it, and 9807117f1b4Smrg * calls dd_function_table::BindTexture. Decrements the old texture reference 9817117f1b4Smrg * count and deletes it if it reaches zero. 9827117f1b4Smrg */ 9837117f1b4Smrgvoid GLAPIENTRY 9847117f1b4Smrg_mesa_BindTexture( GLenum target, GLuint texName ) 9857117f1b4Smrg{ 9867117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 9877117f1b4Smrg const GLuint unit = ctx->Texture.CurrentUnit; 9887117f1b4Smrg struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; 989c1f859d4Smrg struct gl_texture_object *newTexObj = NULL, *defaultTexObj = NULL; 990c1f859d4Smrg GLint targetIndex; 9914a49301eSmrg GLboolean early_out = GL_FALSE; 9927117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 9937117f1b4Smrg 9947117f1b4Smrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 9957117f1b4Smrg _mesa_debug(ctx, "glBindTexture %s %d\n", 9967117f1b4Smrg _mesa_lookup_enum_by_nr(target), (GLint) texName); 9977117f1b4Smrg 998c1f859d4Smrg targetIndex = target_enum_to_index(target); 999c1f859d4Smrg if (targetIndex < 0) { 1000c1f859d4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)"); 1001c1f859d4Smrg return; 1002c1f859d4Smrg } 1003c1f859d4Smrg assert(targetIndex < NUM_TEXTURE_TARGETS); 1004c1f859d4Smrg defaultTexObj = ctx->Shared->DefaultTex[targetIndex]; 1005c1f859d4Smrg 10067117f1b4Smrg /* 10077117f1b4Smrg * Get pointer to new texture object (newTexObj) 10087117f1b4Smrg */ 10097117f1b4Smrg if (texName == 0) { 1010c1f859d4Smrg newTexObj = defaultTexObj; 10117117f1b4Smrg } 10127117f1b4Smrg else { 10137117f1b4Smrg /* non-default texture object */ 10147117f1b4Smrg newTexObj = _mesa_lookup_texture(ctx, texName); 10157117f1b4Smrg if (newTexObj) { 10167117f1b4Smrg /* error checking */ 10177117f1b4Smrg if (newTexObj->Target != 0 && newTexObj->Target != target) { 1018c1f859d4Smrg /* the named texture object's target doesn't match the given target */ 10197117f1b4Smrg _mesa_error( ctx, GL_INVALID_OPERATION, 1020c1f859d4Smrg "glBindTexture(target mismatch)" ); 10217117f1b4Smrg return; 10227117f1b4Smrg } 1023c1f859d4Smrg if (newTexObj->Target == 0) { 1024c1f859d4Smrg finish_texture_init(ctx, target, newTexObj); 10257117f1b4Smrg } 10267117f1b4Smrg } 10277117f1b4Smrg else { 10287117f1b4Smrg /* if this is a new texture id, allocate a texture object now */ 10297117f1b4Smrg newTexObj = (*ctx->Driver.NewTextureObject)(ctx, texName, target); 10307117f1b4Smrg if (!newTexObj) { 10317117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture"); 10327117f1b4Smrg return; 10337117f1b4Smrg } 10347117f1b4Smrg 10357117f1b4Smrg /* and insert it into hash table */ 10367117f1b4Smrg _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 10377117f1b4Smrg _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj); 10387117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 10397117f1b4Smrg } 10407117f1b4Smrg newTexObj->Target = target; 10417117f1b4Smrg } 10427117f1b4Smrg 10437117f1b4Smrg assert(valid_texture_object(newTexObj)); 10447117f1b4Smrg 10454a49301eSmrg _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 10464a49301eSmrg if ((ctx->Shared->RefCount == 1) 10474a49301eSmrg && (newTexObj == texUnit->CurrentTex[targetIndex])) { 10484a49301eSmrg early_out = GL_TRUE; 10494a49301eSmrg } 10504a49301eSmrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 10514a49301eSmrg 10524a49301eSmrg if (early_out) { 10534a49301eSmrg return; 10544a49301eSmrg } 10554a49301eSmrg 10567117f1b4Smrg /* flush before changing binding */ 10577117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_TEXTURE); 10587117f1b4Smrg 10597117f1b4Smrg /* Do the actual binding. The refcount on the previously bound 10607117f1b4Smrg * texture object will be decremented. It'll be deleted if the 10617117f1b4Smrg * count hits zero. 10627117f1b4Smrg */ 1063c1f859d4Smrg _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], newTexObj); 1064c1f859d4Smrg ASSERT(texUnit->CurrentTex[targetIndex]); 10657117f1b4Smrg 10667117f1b4Smrg /* Pass BindTexture call to device driver */ 10677117f1b4Smrg if (ctx->Driver.BindTexture) 10687117f1b4Smrg (*ctx->Driver.BindTexture)( ctx, target, newTexObj ); 10697117f1b4Smrg} 10707117f1b4Smrg 10717117f1b4Smrg 10727117f1b4Smrg/** 10737117f1b4Smrg * Set texture priorities. 10747117f1b4Smrg * 10757117f1b4Smrg * \param n number of textures. 10767117f1b4Smrg * \param texName texture names. 10777117f1b4Smrg * \param priorities corresponding texture priorities. 10787117f1b4Smrg * 10797117f1b4Smrg * \sa glPrioritizeTextures(). 10807117f1b4Smrg * 10817117f1b4Smrg * Looks up each texture in the hash, clamps the corresponding priority between 10827117f1b4Smrg * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture. 10837117f1b4Smrg */ 10847117f1b4Smrgvoid GLAPIENTRY 10857117f1b4Smrg_mesa_PrioritizeTextures( GLsizei n, const GLuint *texName, 10867117f1b4Smrg const GLclampf *priorities ) 10877117f1b4Smrg{ 10887117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 10897117f1b4Smrg GLint i; 10907117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 10917117f1b4Smrg 10927117f1b4Smrg if (n < 0) { 10937117f1b4Smrg _mesa_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" ); 10947117f1b4Smrg return; 10957117f1b4Smrg } 10967117f1b4Smrg 10977117f1b4Smrg if (!priorities) 10987117f1b4Smrg return; 10997117f1b4Smrg 11007117f1b4Smrg for (i = 0; i < n; i++) { 11017117f1b4Smrg if (texName[i] > 0) { 11027117f1b4Smrg struct gl_texture_object *t = _mesa_lookup_texture(ctx, texName[i]); 11037117f1b4Smrg if (t) { 11047117f1b4Smrg t->Priority = CLAMP( priorities[i], 0.0F, 1.0F ); 11057117f1b4Smrg } 11067117f1b4Smrg } 11077117f1b4Smrg } 11087117f1b4Smrg 11097117f1b4Smrg ctx->NewState |= _NEW_TEXTURE; 11107117f1b4Smrg} 11117117f1b4Smrg 11127117f1b4Smrg/** 11137117f1b4Smrg * See if textures are loaded in texture memory. 11147117f1b4Smrg * 11157117f1b4Smrg * \param n number of textures to query. 11167117f1b4Smrg * \param texName array with the texture names. 11177117f1b4Smrg * \param residences array which will hold the residence status. 11187117f1b4Smrg * 11197117f1b4Smrg * \return GL_TRUE if all textures are resident and \p residences is left unchanged, 11207117f1b4Smrg * 11217117f1b4Smrg * \sa glAreTexturesResident(). 11227117f1b4Smrg * 11237117f1b4Smrg * Looks up each texture in the hash and calls 11247117f1b4Smrg * dd_function_table::IsTextureResident. 11257117f1b4Smrg */ 11267117f1b4SmrgGLboolean GLAPIENTRY 11277117f1b4Smrg_mesa_AreTexturesResident(GLsizei n, const GLuint *texName, 11287117f1b4Smrg GLboolean *residences) 11297117f1b4Smrg{ 11307117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 11317117f1b4Smrg GLboolean allResident = GL_TRUE; 11327117f1b4Smrg GLint i, j; 11337117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 11347117f1b4Smrg 11357117f1b4Smrg if (n < 0) { 11367117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)"); 11377117f1b4Smrg return GL_FALSE; 11387117f1b4Smrg } 11397117f1b4Smrg 11407117f1b4Smrg if (!texName || !residences) 11417117f1b4Smrg return GL_FALSE; 11427117f1b4Smrg 11437117f1b4Smrg for (i = 0; i < n; i++) { 11447117f1b4Smrg struct gl_texture_object *t; 11457117f1b4Smrg if (texName[i] == 0) { 11467117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident"); 11477117f1b4Smrg return GL_FALSE; 11487117f1b4Smrg } 11497117f1b4Smrg t = _mesa_lookup_texture(ctx, texName[i]); 11507117f1b4Smrg if (!t) { 11517117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident"); 11527117f1b4Smrg return GL_FALSE; 11537117f1b4Smrg } 11547117f1b4Smrg if (!ctx->Driver.IsTextureResident || 11557117f1b4Smrg ctx->Driver.IsTextureResident(ctx, t)) { 11567117f1b4Smrg /* The texture is resident */ 11577117f1b4Smrg if (!allResident) 11587117f1b4Smrg residences[i] = GL_TRUE; 11597117f1b4Smrg } 11607117f1b4Smrg else { 11617117f1b4Smrg /* The texture is not resident */ 11627117f1b4Smrg if (allResident) { 11637117f1b4Smrg allResident = GL_FALSE; 11647117f1b4Smrg for (j = 0; j < i; j++) 11657117f1b4Smrg residences[j] = GL_TRUE; 11667117f1b4Smrg } 11677117f1b4Smrg residences[i] = GL_FALSE; 11687117f1b4Smrg } 11697117f1b4Smrg } 11707117f1b4Smrg 11717117f1b4Smrg return allResident; 11727117f1b4Smrg} 11737117f1b4Smrg 11747117f1b4Smrg/** 11757117f1b4Smrg * See if a name corresponds to a texture. 11767117f1b4Smrg * 11777117f1b4Smrg * \param texture texture name. 11787117f1b4Smrg * 11797117f1b4Smrg * \return GL_TRUE if texture name corresponds to a texture, or GL_FALSE 11807117f1b4Smrg * otherwise. 11817117f1b4Smrg * 11827117f1b4Smrg * \sa glIsTexture(). 11837117f1b4Smrg * 11847117f1b4Smrg * Calls _mesa_HashLookup(). 11857117f1b4Smrg */ 11867117f1b4SmrgGLboolean GLAPIENTRY 11877117f1b4Smrg_mesa_IsTexture( GLuint texture ) 11887117f1b4Smrg{ 11897117f1b4Smrg struct gl_texture_object *t; 11907117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 11917117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 11927117f1b4Smrg 11937117f1b4Smrg if (!texture) 11947117f1b4Smrg return GL_FALSE; 11957117f1b4Smrg 11967117f1b4Smrg t = _mesa_lookup_texture(ctx, texture); 11977117f1b4Smrg 11987117f1b4Smrg /* IsTexture is true only after object has been bound once. */ 11997117f1b4Smrg return t && t->Target; 12007117f1b4Smrg} 12017117f1b4Smrg 1202c1f859d4Smrg 1203c1f859d4Smrg/** 12044a49301eSmrg * Simplest implementation of texture locking: grab the shared tex 12054a49301eSmrg * mutex. Examine the shared context state timestamp and if there has 12064a49301eSmrg * been a change, set the appropriate bits in ctx->NewState. 12077117f1b4Smrg * 1208c1f859d4Smrg * This is used to deal with synchronizing things when a texture object 1209c1f859d4Smrg * is used/modified by different contexts (or threads) which are sharing 1210c1f859d4Smrg * the texture. 1211c1f859d4Smrg * 1212c1f859d4Smrg * See also _mesa_lock/unlock_texture() in teximage.h 12137117f1b4Smrg */ 1214c1f859d4Smrgvoid 1215c1f859d4Smrg_mesa_lock_context_textures( GLcontext *ctx ) 12167117f1b4Smrg{ 12177117f1b4Smrg _glthread_LOCK_MUTEX(ctx->Shared->TexMutex); 12187117f1b4Smrg 12197117f1b4Smrg if (ctx->Shared->TextureStateStamp != ctx->TextureStateTimestamp) { 12207117f1b4Smrg ctx->NewState |= _NEW_TEXTURE; 12217117f1b4Smrg ctx->TextureStateTimestamp = ctx->Shared->TextureStateStamp; 12227117f1b4Smrg } 12237117f1b4Smrg} 12247117f1b4Smrg 12257117f1b4Smrg 1226c1f859d4Smrgvoid 1227c1f859d4Smrg_mesa_unlock_context_textures( GLcontext *ctx ) 12287117f1b4Smrg{ 12297117f1b4Smrg assert(ctx->Shared->TextureStateStamp == ctx->TextureStateTimestamp); 12307117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->TexMutex); 12317117f1b4Smrg} 12327117f1b4Smrg 12337117f1b4Smrg/*@}*/ 12347117f1b4Smrg 12357117f1b4Smrg 1236