texobj.c revision 3464ebd5
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" 323464ebd5Sriastradh#include "bufferobj.h" 337117f1b4Smrg#include "colortab.h" 347117f1b4Smrg#include "context.h" 357117f1b4Smrg#include "enums.h" 367117f1b4Smrg#include "fbobject.h" 374a49301eSmrg#include "formats.h" 387117f1b4Smrg#include "hash.h" 397117f1b4Smrg#include "imports.h" 407117f1b4Smrg#include "macros.h" 417117f1b4Smrg#include "teximage.h" 427117f1b4Smrg#include "texobj.h" 433464ebd5Sriastradh#include "texstate.h" 447117f1b4Smrg#include "mtypes.h" 453464ebd5Sriastradh#include "program/prog_instruction.h" 464a49301eSmrg 477117f1b4Smrg 487117f1b4Smrg 497117f1b4Smrg/**********************************************************************/ 507117f1b4Smrg/** \name Internal functions */ 517117f1b4Smrg/*@{*/ 527117f1b4Smrg 537117f1b4Smrg 547117f1b4Smrg/** 557117f1b4Smrg * Return the gl_texture_object for a given ID. 567117f1b4Smrg */ 577117f1b4Smrgstruct gl_texture_object * 583464ebd5Sriastradh_mesa_lookup_texture(struct gl_context *ctx, GLuint id) 597117f1b4Smrg{ 607117f1b4Smrg return (struct gl_texture_object *) 617117f1b4Smrg _mesa_HashLookup(ctx->Shared->TexObjects, id); 627117f1b4Smrg} 637117f1b4Smrg 647117f1b4Smrg 657117f1b4Smrg 667117f1b4Smrg/** 677117f1b4Smrg * Allocate and initialize a new texture object. But don't put it into the 687117f1b4Smrg * texture object hash table. 697117f1b4Smrg * 707117f1b4Smrg * Called via ctx->Driver.NewTextureObject, unless overridden by a device 717117f1b4Smrg * driver. 727117f1b4Smrg * 737117f1b4Smrg * \param shared the shared GL state structure to contain the texture object 747117f1b4Smrg * \param name integer name for the texture object 757117f1b4Smrg * \param target either GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, 767117f1b4Smrg * GL_TEXTURE_CUBE_MAP_ARB or GL_TEXTURE_RECTANGLE_NV. zero is ok for the sake 777117f1b4Smrg * of GenTextures() 787117f1b4Smrg * 797117f1b4Smrg * \return pointer to new texture object. 807117f1b4Smrg */ 817117f1b4Smrgstruct gl_texture_object * 823464ebd5Sriastradh_mesa_new_texture_object( struct gl_context *ctx, GLuint name, GLenum target ) 837117f1b4Smrg{ 847117f1b4Smrg struct gl_texture_object *obj; 857117f1b4Smrg (void) ctx; 867117f1b4Smrg obj = MALLOC_STRUCT(gl_texture_object); 877117f1b4Smrg _mesa_initialize_texture_object(obj, name, target); 887117f1b4Smrg return obj; 897117f1b4Smrg} 907117f1b4Smrg 917117f1b4Smrg 927117f1b4Smrg/** 937117f1b4Smrg * Initialize a new texture object to default values. 947117f1b4Smrg * \param obj the texture object 957117f1b4Smrg * \param name the texture name 967117f1b4Smrg * \param target the texture target 977117f1b4Smrg */ 987117f1b4Smrgvoid 997117f1b4Smrg_mesa_initialize_texture_object( struct gl_texture_object *obj, 1007117f1b4Smrg GLuint name, GLenum target ) 1017117f1b4Smrg{ 1027117f1b4Smrg ASSERT(target == 0 || 1037117f1b4Smrg target == GL_TEXTURE_1D || 1047117f1b4Smrg target == GL_TEXTURE_2D || 1057117f1b4Smrg target == GL_TEXTURE_3D || 1067117f1b4Smrg target == GL_TEXTURE_CUBE_MAP_ARB || 107c1f859d4Smrg target == GL_TEXTURE_RECTANGLE_NV || 108c1f859d4Smrg target == GL_TEXTURE_1D_ARRAY_EXT || 1093464ebd5Sriastradh target == GL_TEXTURE_2D_ARRAY_EXT || 1103464ebd5Sriastradh target == GL_TEXTURE_BUFFER); 1117117f1b4Smrg 112cdc920a0Smrg memset(obj, 0, sizeof(*obj)); 1137117f1b4Smrg /* init the non-zero fields */ 1147117f1b4Smrg _glthread_INIT_MUTEX(obj->Mutex); 1157117f1b4Smrg obj->RefCount = 1; 1167117f1b4Smrg obj->Name = name; 1177117f1b4Smrg obj->Target = target; 1187117f1b4Smrg obj->Priority = 1.0F; 1193464ebd5Sriastradh obj->BaseLevel = 0; 1203464ebd5Sriastradh obj->MaxLevel = 1000; 1213464ebd5Sriastradh 1223464ebd5Sriastradh /* sampler state */ 1237117f1b4Smrg if (target == GL_TEXTURE_RECTANGLE_NV) { 1243464ebd5Sriastradh obj->Sampler.WrapS = GL_CLAMP_TO_EDGE; 1253464ebd5Sriastradh obj->Sampler.WrapT = GL_CLAMP_TO_EDGE; 1263464ebd5Sriastradh obj->Sampler.WrapR = GL_CLAMP_TO_EDGE; 1273464ebd5Sriastradh obj->Sampler.MinFilter = GL_LINEAR; 1287117f1b4Smrg } 1297117f1b4Smrg else { 1303464ebd5Sriastradh obj->Sampler.WrapS = GL_REPEAT; 1313464ebd5Sriastradh obj->Sampler.WrapT = GL_REPEAT; 1323464ebd5Sriastradh obj->Sampler.WrapR = GL_REPEAT; 1333464ebd5Sriastradh obj->Sampler.MinFilter = GL_NEAREST_MIPMAP_LINEAR; 1347117f1b4Smrg } 1353464ebd5Sriastradh obj->Sampler.MagFilter = GL_LINEAR; 1363464ebd5Sriastradh obj->Sampler.MinLod = -1000.0; 1373464ebd5Sriastradh obj->Sampler.MaxLod = 1000.0; 1383464ebd5Sriastradh obj->Sampler.LodBias = 0.0; 1393464ebd5Sriastradh obj->Sampler.MaxAnisotropy = 1.0; 1403464ebd5Sriastradh obj->Sampler.CompareMode = GL_NONE; /* ARB_shadow */ 1413464ebd5Sriastradh obj->Sampler.CompareFunc = GL_LEQUAL; /* ARB_shadow */ 1423464ebd5Sriastradh obj->Sampler.CompareFailValue = 0.0F; /* ARB_shadow_ambient */ 1433464ebd5Sriastradh obj->Sampler.DepthMode = GL_LUMINANCE; /* ARB_depth_texture */ 1443464ebd5Sriastradh obj->Sampler.CubeMapSeamless = GL_FALSE; 1454a49301eSmrg obj->Swizzle[0] = GL_RED; 1464a49301eSmrg obj->Swizzle[1] = GL_GREEN; 1474a49301eSmrg obj->Swizzle[2] = GL_BLUE; 1484a49301eSmrg obj->Swizzle[3] = GL_ALPHA; 1494a49301eSmrg obj->_Swizzle = SWIZZLE_NOOP; 1503464ebd5Sriastradh obj->Sampler.sRGBDecode = GL_DECODE_EXT; 151c1f859d4Smrg} 152c1f859d4Smrg 153c1f859d4Smrg 154c1f859d4Smrg/** 155c1f859d4Smrg * Some texture initialization can't be finished until we know which 156c1f859d4Smrg * target it's getting bound to (GL_TEXTURE_1D/2D/etc). 157c1f859d4Smrg */ 158c1f859d4Smrgstatic void 1593464ebd5Sriastradhfinish_texture_init(struct gl_context *ctx, GLenum target, 160c1f859d4Smrg struct gl_texture_object *obj) 161c1f859d4Smrg{ 162c1f859d4Smrg assert(obj->Target == 0); 163c1f859d4Smrg 164c1f859d4Smrg if (target == GL_TEXTURE_RECTANGLE_NV) { 165c1f859d4Smrg /* have to init wrap and filter state here - kind of klunky */ 1663464ebd5Sriastradh obj->Sampler.WrapS = GL_CLAMP_TO_EDGE; 1673464ebd5Sriastradh obj->Sampler.WrapT = GL_CLAMP_TO_EDGE; 1683464ebd5Sriastradh obj->Sampler.WrapR = GL_CLAMP_TO_EDGE; 1693464ebd5Sriastradh obj->Sampler.MinFilter = GL_LINEAR; 170c1f859d4Smrg if (ctx->Driver.TexParameter) { 171c1f859d4Smrg static const GLfloat fparam_wrap[1] = {(GLfloat) GL_CLAMP_TO_EDGE}; 172c1f859d4Smrg static const GLfloat fparam_filter[1] = {(GLfloat) GL_LINEAR}; 173c1f859d4Smrg ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_S, fparam_wrap); 174c1f859d4Smrg ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_T, fparam_wrap); 175c1f859d4Smrg ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_R, fparam_wrap); 176c1f859d4Smrg ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_MIN_FILTER, fparam_filter); 177c1f859d4Smrg } 178c1f859d4Smrg } 1797117f1b4Smrg} 1807117f1b4Smrg 1817117f1b4Smrg 1827117f1b4Smrg/** 1837117f1b4Smrg * Deallocate a texture object struct. It should have already been 1847117f1b4Smrg * removed from the texture object pool. 185c1f859d4Smrg * Called via ctx->Driver.DeleteTexture() if not overriden by a driver. 1867117f1b4Smrg * 1877117f1b4Smrg * \param shared the shared GL state to which the object belongs. 1884a49301eSmrg * \param texObj the texture object to delete. 1897117f1b4Smrg */ 1907117f1b4Smrgvoid 1913464ebd5Sriastradh_mesa_delete_texture_object(struct gl_context *ctx, 1923464ebd5Sriastradh struct gl_texture_object *texObj) 1937117f1b4Smrg{ 1947117f1b4Smrg GLuint i, face; 1957117f1b4Smrg 1967117f1b4Smrg /* Set Target to an invalid value. With some assertions elsewhere 1977117f1b4Smrg * we can try to detect possible use of deleted textures. 1987117f1b4Smrg */ 1997117f1b4Smrg texObj->Target = 0x99; 2007117f1b4Smrg 2017117f1b4Smrg _mesa_free_colortable_data(&texObj->Palette); 2027117f1b4Smrg 2037117f1b4Smrg /* free the texture images */ 2047117f1b4Smrg for (face = 0; face < 6; face++) { 2057117f1b4Smrg for (i = 0; i < MAX_TEXTURE_LEVELS; i++) { 2063464ebd5Sriastradh if (texObj->Image[face][i]) { 2073464ebd5Sriastradh _mesa_delete_texture_image( ctx, texObj->Image[face][i] ); 2083464ebd5Sriastradh } 2097117f1b4Smrg } 2107117f1b4Smrg } 2117117f1b4Smrg 2123464ebd5Sriastradh _mesa_reference_buffer_object(ctx, &texObj->BufferObject, NULL); 2133464ebd5Sriastradh 2147117f1b4Smrg /* destroy the mutex -- it may have allocated memory (eg on bsd) */ 2157117f1b4Smrg _glthread_DESTROY_MUTEX(texObj->Mutex); 2167117f1b4Smrg 2177117f1b4Smrg /* free this object */ 218cdc920a0Smrg free(texObj); 2197117f1b4Smrg} 2207117f1b4Smrg 2217117f1b4Smrg 2227117f1b4Smrg 2237117f1b4Smrg/** 2247117f1b4Smrg * Copy texture object state from one texture object to another. 2257117f1b4Smrg * Use for glPush/PopAttrib. 2267117f1b4Smrg * 2277117f1b4Smrg * \param dest destination texture object. 2287117f1b4Smrg * \param src source texture object. 2297117f1b4Smrg */ 2307117f1b4Smrgvoid 2317117f1b4Smrg_mesa_copy_texture_object( struct gl_texture_object *dest, 2327117f1b4Smrg const struct gl_texture_object *src ) 2337117f1b4Smrg{ 2347117f1b4Smrg dest->Target = src->Target; 2357117f1b4Smrg dest->Name = src->Name; 2367117f1b4Smrg dest->Priority = src->Priority; 2373464ebd5Sriastradh dest->Sampler.BorderColor.f[0] = src->Sampler.BorderColor.f[0]; 2383464ebd5Sriastradh dest->Sampler.BorderColor.f[1] = src->Sampler.BorderColor.f[1]; 2393464ebd5Sriastradh dest->Sampler.BorderColor.f[2] = src->Sampler.BorderColor.f[2]; 2403464ebd5Sriastradh dest->Sampler.BorderColor.f[3] = src->Sampler.BorderColor.f[3]; 2413464ebd5Sriastradh dest->Sampler.WrapS = src->Sampler.WrapS; 2423464ebd5Sriastradh dest->Sampler.WrapT = src->Sampler.WrapT; 2433464ebd5Sriastradh dest->Sampler.WrapR = src->Sampler.WrapR; 2443464ebd5Sriastradh dest->Sampler.MinFilter = src->Sampler.MinFilter; 2453464ebd5Sriastradh dest->Sampler.MagFilter = src->Sampler.MagFilter; 2463464ebd5Sriastradh dest->Sampler.MinLod = src->Sampler.MinLod; 2473464ebd5Sriastradh dest->Sampler.MaxLod = src->Sampler.MaxLod; 2483464ebd5Sriastradh dest->Sampler.LodBias = src->Sampler.LodBias; 2497117f1b4Smrg dest->BaseLevel = src->BaseLevel; 2507117f1b4Smrg dest->MaxLevel = src->MaxLevel; 2513464ebd5Sriastradh dest->Sampler.MaxAnisotropy = src->Sampler.MaxAnisotropy; 2523464ebd5Sriastradh dest->Sampler.CompareMode = src->Sampler.CompareMode; 2533464ebd5Sriastradh dest->Sampler.CompareFunc = src->Sampler.CompareFunc; 2543464ebd5Sriastradh dest->Sampler.CompareFailValue = src->Sampler.CompareFailValue; 2553464ebd5Sriastradh dest->Sampler.CubeMapSeamless = src->Sampler.CubeMapSeamless; 2563464ebd5Sriastradh dest->Sampler.DepthMode = src->Sampler.DepthMode; 2573464ebd5Sriastradh dest->Sampler.sRGBDecode = src->Sampler.sRGBDecode; 2587117f1b4Smrg dest->_MaxLevel = src->_MaxLevel; 2597117f1b4Smrg dest->_MaxLambda = src->_MaxLambda; 2607117f1b4Smrg dest->GenerateMipmap = src->GenerateMipmap; 2617117f1b4Smrg dest->Palette = src->Palette; 262c1f859d4Smrg dest->_Complete = src->_Complete; 2634a49301eSmrg COPY_4V(dest->Swizzle, src->Swizzle); 2644a49301eSmrg dest->_Swizzle = src->_Swizzle; 2654a49301eSmrg} 2664a49301eSmrg 2674a49301eSmrg 2684a49301eSmrg/** 2693464ebd5Sriastradh * Free all texture images of the given texture object. 2704a49301eSmrg * 2714a49301eSmrg * \param ctx GL context. 2724a49301eSmrg * \param t texture object. 2734a49301eSmrg * 2744a49301eSmrg * \sa _mesa_clear_texture_image(). 2754a49301eSmrg */ 2764a49301eSmrgvoid 2773464ebd5Sriastradh_mesa_clear_texture_object(struct gl_context *ctx, 2783464ebd5Sriastradh struct gl_texture_object *texObj) 2794a49301eSmrg{ 2804a49301eSmrg GLuint i, j; 2814a49301eSmrg 2824a49301eSmrg if (texObj->Target == 0) 2834a49301eSmrg return; 2844a49301eSmrg 2854a49301eSmrg for (i = 0; i < MAX_FACES; i++) { 2864a49301eSmrg for (j = 0; j < MAX_TEXTURE_LEVELS; j++) { 2874a49301eSmrg struct gl_texture_image *texImage = texObj->Image[i][j]; 2884a49301eSmrg if (texImage) 2894a49301eSmrg _mesa_clear_texture_image(ctx, texImage); 2904a49301eSmrg } 2914a49301eSmrg } 2927117f1b4Smrg} 2937117f1b4Smrg 2947117f1b4Smrg 2957117f1b4Smrg/** 2967117f1b4Smrg * Check if the given texture object is valid by examining its Target field. 2977117f1b4Smrg * For debugging only. 2987117f1b4Smrg */ 2997117f1b4Smrgstatic GLboolean 3007117f1b4Smrgvalid_texture_object(const struct gl_texture_object *tex) 3017117f1b4Smrg{ 3027117f1b4Smrg switch (tex->Target) { 3037117f1b4Smrg case 0: 3047117f1b4Smrg case GL_TEXTURE_1D: 3057117f1b4Smrg case GL_TEXTURE_2D: 3067117f1b4Smrg case GL_TEXTURE_3D: 3077117f1b4Smrg case GL_TEXTURE_CUBE_MAP_ARB: 3087117f1b4Smrg case GL_TEXTURE_RECTANGLE_NV: 309c1f859d4Smrg case GL_TEXTURE_1D_ARRAY_EXT: 310c1f859d4Smrg case GL_TEXTURE_2D_ARRAY_EXT: 3113464ebd5Sriastradh case GL_TEXTURE_BUFFER: 3127117f1b4Smrg return GL_TRUE; 3137117f1b4Smrg case 0x99: 3147117f1b4Smrg _mesa_problem(NULL, "invalid reference to a deleted texture object"); 3157117f1b4Smrg return GL_FALSE; 3167117f1b4Smrg default: 3174a49301eSmrg _mesa_problem(NULL, "invalid texture object Target 0x%x, Id = %u", 3184a49301eSmrg tex->Target, tex->Name); 3197117f1b4Smrg return GL_FALSE; 3207117f1b4Smrg } 3217117f1b4Smrg} 3227117f1b4Smrg 3237117f1b4Smrg 3247117f1b4Smrg/** 3257117f1b4Smrg * Reference (or unreference) a texture object. 3267117f1b4Smrg * If '*ptr', decrement *ptr's refcount (and delete if it becomes zero). 3277117f1b4Smrg * If 'tex' is non-null, increment its refcount. 3287117f1b4Smrg */ 3297117f1b4Smrgvoid 3307117f1b4Smrg_mesa_reference_texobj(struct gl_texture_object **ptr, 3317117f1b4Smrg struct gl_texture_object *tex) 3327117f1b4Smrg{ 3337117f1b4Smrg assert(ptr); 3347117f1b4Smrg if (*ptr == tex) { 3357117f1b4Smrg /* no change */ 3367117f1b4Smrg return; 3377117f1b4Smrg } 3387117f1b4Smrg 3397117f1b4Smrg if (*ptr) { 3407117f1b4Smrg /* Unreference the old texture */ 3417117f1b4Smrg GLboolean deleteFlag = GL_FALSE; 3427117f1b4Smrg struct gl_texture_object *oldTex = *ptr; 3437117f1b4Smrg 3444a49301eSmrg ASSERT(valid_texture_object(oldTex)); 3453464ebd5Sriastradh (void) valid_texture_object; /* silence warning in release builds */ 3467117f1b4Smrg 3477117f1b4Smrg _glthread_LOCK_MUTEX(oldTex->Mutex); 3487117f1b4Smrg ASSERT(oldTex->RefCount > 0); 3497117f1b4Smrg oldTex->RefCount--; 3507117f1b4Smrg 3517117f1b4Smrg deleteFlag = (oldTex->RefCount == 0); 3527117f1b4Smrg _glthread_UNLOCK_MUTEX(oldTex->Mutex); 3537117f1b4Smrg 3547117f1b4Smrg if (deleteFlag) { 3557117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 3567117f1b4Smrg if (ctx) 3577117f1b4Smrg ctx->Driver.DeleteTexture(ctx, oldTex); 3587117f1b4Smrg else 3597117f1b4Smrg _mesa_problem(NULL, "Unable to delete texture, no context"); 3607117f1b4Smrg } 3617117f1b4Smrg 3627117f1b4Smrg *ptr = NULL; 3637117f1b4Smrg } 3647117f1b4Smrg assert(!*ptr); 3657117f1b4Smrg 3667117f1b4Smrg if (tex) { 3677117f1b4Smrg /* reference new texture */ 3684a49301eSmrg ASSERT(valid_texture_object(tex)); 3697117f1b4Smrg _glthread_LOCK_MUTEX(tex->Mutex); 3707117f1b4Smrg if (tex->RefCount == 0) { 3717117f1b4Smrg /* this texture's being deleted (look just above) */ 3727117f1b4Smrg /* Not sure this can every really happen. Warn if it does. */ 3737117f1b4Smrg _mesa_problem(NULL, "referencing deleted texture object"); 3747117f1b4Smrg *ptr = NULL; 3757117f1b4Smrg } 3767117f1b4Smrg else { 3777117f1b4Smrg tex->RefCount++; 3787117f1b4Smrg *ptr = tex; 3797117f1b4Smrg } 3807117f1b4Smrg _glthread_UNLOCK_MUTEX(tex->Mutex); 3817117f1b4Smrg } 3827117f1b4Smrg} 3837117f1b4Smrg 3847117f1b4Smrg 3857117f1b4Smrg 3867117f1b4Smrg/** 3873464ebd5Sriastradh * Mark a texture object as incomplete. 3883464ebd5Sriastradh * \param t texture object 3893464ebd5Sriastradh * \param fmt... string describing why it's incomplete (for debugging). 3907117f1b4Smrg */ 3917117f1b4Smrgstatic void 3923464ebd5Sriastradhincomplete(struct gl_texture_object *t, const char *fmt, ...) 3937117f1b4Smrg{ 3943464ebd5Sriastradh#if 0 3953464ebd5Sriastradh va_list args; 3963464ebd5Sriastradh char s[100]; 3973464ebd5Sriastradh 3983464ebd5Sriastradh va_start(args, fmt); 3993464ebd5Sriastradh vsnprintf(s, sizeof(s), fmt, args); 4003464ebd5Sriastradh va_end(args); 4013464ebd5Sriastradh 4023464ebd5Sriastradh printf("Texture Obj %d incomplete because: %s\n", t->Name, s); 4037117f1b4Smrg#endif 4043464ebd5Sriastradh t->_Complete = GL_FALSE; 4053464ebd5Sriastradh} 4067117f1b4Smrg 4077117f1b4Smrg 4087117f1b4Smrg/** 4097117f1b4Smrg * Examine a texture object to determine if it is complete. 4107117f1b4Smrg * 4117117f1b4Smrg * The gl_texture_object::Complete flag will be set to GL_TRUE or GL_FALSE 4127117f1b4Smrg * accordingly. 4137117f1b4Smrg * 4147117f1b4Smrg * \param ctx GL context. 4157117f1b4Smrg * \param t texture object. 4167117f1b4Smrg * 4177117f1b4Smrg * According to the texture target, verifies that each of the mipmaps is 4187117f1b4Smrg * present and has the expected size. 4197117f1b4Smrg */ 4207117f1b4Smrgvoid 4213464ebd5Sriastradh_mesa_test_texobj_completeness( const struct gl_context *ctx, 4227117f1b4Smrg struct gl_texture_object *t ) 4237117f1b4Smrg{ 4247117f1b4Smrg const GLint baseLevel = t->BaseLevel; 4257117f1b4Smrg GLint maxLog2 = 0, maxLevels = 0; 4267117f1b4Smrg 427c1f859d4Smrg t->_Complete = GL_TRUE; /* be optimistic */ 428c1f859d4Smrg 429c1f859d4Smrg /* Detect cases where the application set the base level to an invalid 430c1f859d4Smrg * value. 431c1f859d4Smrg */ 4324a49301eSmrg if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS)) { 4333464ebd5Sriastradh incomplete(t, "base level = %d is invalid", baseLevel); 434c1f859d4Smrg return; 435c1f859d4Smrg } 4367117f1b4Smrg 4377117f1b4Smrg /* Always need the base level image */ 4387117f1b4Smrg if (!t->Image[0][baseLevel]) { 4393464ebd5Sriastradh incomplete(t, "Image[baseLevel=%d] == NULL", baseLevel); 4407117f1b4Smrg return; 4417117f1b4Smrg } 4427117f1b4Smrg 4437117f1b4Smrg /* Check width/height/depth for zero */ 4447117f1b4Smrg if (t->Image[0][baseLevel]->Width == 0 || 4457117f1b4Smrg t->Image[0][baseLevel]->Height == 0 || 4467117f1b4Smrg t->Image[0][baseLevel]->Depth == 0) { 4477117f1b4Smrg incomplete(t, "texture width = 0"); 4487117f1b4Smrg return; 4497117f1b4Smrg } 4507117f1b4Smrg 4517117f1b4Smrg /* Compute _MaxLevel */ 452c1f859d4Smrg if ((t->Target == GL_TEXTURE_1D) || 453c1f859d4Smrg (t->Target == GL_TEXTURE_1D_ARRAY_EXT)) { 4547117f1b4Smrg maxLog2 = t->Image[0][baseLevel]->WidthLog2; 4557117f1b4Smrg maxLevels = ctx->Const.MaxTextureLevels; 4567117f1b4Smrg } 457c1f859d4Smrg else if ((t->Target == GL_TEXTURE_2D) || 4583464ebd5Sriastradh (t->Target == GL_TEXTURE_2D_ARRAY_EXT)) { 4597117f1b4Smrg maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2, 4607117f1b4Smrg t->Image[0][baseLevel]->HeightLog2); 4617117f1b4Smrg maxLevels = ctx->Const.MaxTextureLevels; 4627117f1b4Smrg } 4637117f1b4Smrg else if (t->Target == GL_TEXTURE_3D) { 4647117f1b4Smrg GLint max = MAX2(t->Image[0][baseLevel]->WidthLog2, 4657117f1b4Smrg t->Image[0][baseLevel]->HeightLog2); 4667117f1b4Smrg maxLog2 = MAX2(max, (GLint)(t->Image[0][baseLevel]->DepthLog2)); 4677117f1b4Smrg maxLevels = ctx->Const.Max3DTextureLevels; 4687117f1b4Smrg } 4697117f1b4Smrg else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) { 4707117f1b4Smrg maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2, 4717117f1b4Smrg t->Image[0][baseLevel]->HeightLog2); 4727117f1b4Smrg maxLevels = ctx->Const.MaxCubeTextureLevels; 4737117f1b4Smrg } 4747117f1b4Smrg else if (t->Target == GL_TEXTURE_RECTANGLE_NV) { 4757117f1b4Smrg maxLog2 = 0; /* not applicable */ 4767117f1b4Smrg maxLevels = 1; /* no mipmapping */ 4777117f1b4Smrg } 4787117f1b4Smrg else { 4797117f1b4Smrg _mesa_problem(ctx, "Bad t->Target in _mesa_test_texobj_completeness"); 4807117f1b4Smrg return; 4817117f1b4Smrg } 4827117f1b4Smrg 4837117f1b4Smrg ASSERT(maxLevels > 0); 4847117f1b4Smrg 4853464ebd5Sriastradh if (t->MaxLevel < t->BaseLevel) { 4863464ebd5Sriastradh incomplete(t, "MAX_LEVEL (%d) < BASE_LEVEL (%d)", 4873464ebd5Sriastradh t->MaxLevel, t->BaseLevel); 4883464ebd5Sriastradh return; 4893464ebd5Sriastradh } 4903464ebd5Sriastradh 4917117f1b4Smrg t->_MaxLevel = baseLevel + maxLog2; 4927117f1b4Smrg t->_MaxLevel = MIN2(t->_MaxLevel, t->MaxLevel); 4937117f1b4Smrg t->_MaxLevel = MIN2(t->_MaxLevel, maxLevels - 1); 4947117f1b4Smrg 4957117f1b4Smrg /* Compute _MaxLambda = q - b (see the 1.2 spec) used during mipmapping */ 4967117f1b4Smrg t->_MaxLambda = (GLfloat) (t->_MaxLevel - t->BaseLevel); 4977117f1b4Smrg 4987117f1b4Smrg if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) { 4997117f1b4Smrg /* make sure that all six cube map level 0 images are the same size */ 5007117f1b4Smrg const GLuint w = t->Image[0][baseLevel]->Width2; 5017117f1b4Smrg const GLuint h = t->Image[0][baseLevel]->Height2; 5027117f1b4Smrg GLuint face; 5037117f1b4Smrg for (face = 1; face < 6; face++) { 5043464ebd5Sriastradh if (t->Image[face][baseLevel] == NULL || 5053464ebd5Sriastradh t->Image[face][baseLevel]->Width2 != w || 5063464ebd5Sriastradh t->Image[face][baseLevel]->Height2 != h) { 5073464ebd5Sriastradh incomplete(t, "Cube face missing or mismatched size"); 5083464ebd5Sriastradh return; 5093464ebd5Sriastradh } 5107117f1b4Smrg } 5117117f1b4Smrg } 5127117f1b4Smrg 5137117f1b4Smrg /* extra checking for mipmaps */ 5143464ebd5Sriastradh if (t->Sampler.MinFilter != GL_NEAREST && t->Sampler.MinFilter != GL_LINEAR) { 5157117f1b4Smrg /* 5167117f1b4Smrg * Mipmapping: determine if we have a complete set of mipmaps 5177117f1b4Smrg */ 5187117f1b4Smrg GLint i; 5197117f1b4Smrg GLint minLevel = baseLevel; 5207117f1b4Smrg GLint maxLevel = t->_MaxLevel; 5217117f1b4Smrg 5227117f1b4Smrg if (minLevel > maxLevel) { 5237117f1b4Smrg incomplete(t, "minLevel > maxLevel"); 5247117f1b4Smrg return; 5257117f1b4Smrg } 5267117f1b4Smrg 5277117f1b4Smrg /* Test dimension-independent attributes */ 5287117f1b4Smrg for (i = minLevel; i <= maxLevel; i++) { 5297117f1b4Smrg if (t->Image[0][i]) { 5307117f1b4Smrg if (t->Image[0][i]->TexFormat != t->Image[0][baseLevel]->TexFormat) { 5317117f1b4Smrg incomplete(t, "Format[i] != Format[baseLevel]"); 5327117f1b4Smrg return; 5337117f1b4Smrg } 5347117f1b4Smrg if (t->Image[0][i]->Border != t->Image[0][baseLevel]->Border) { 5357117f1b4Smrg incomplete(t, "Border[i] != Border[baseLevel]"); 5367117f1b4Smrg return; 5377117f1b4Smrg } 5387117f1b4Smrg } 5397117f1b4Smrg } 5407117f1b4Smrg 5417117f1b4Smrg /* Test things which depend on number of texture image dimensions */ 542c1f859d4Smrg if ((t->Target == GL_TEXTURE_1D) || 543c1f859d4Smrg (t->Target == GL_TEXTURE_1D_ARRAY_EXT)) { 5447117f1b4Smrg /* Test 1-D mipmaps */ 5457117f1b4Smrg GLuint width = t->Image[0][baseLevel]->Width2; 5467117f1b4Smrg for (i = baseLevel + 1; i < maxLevels; i++) { 5477117f1b4Smrg if (width > 1) { 5487117f1b4Smrg width /= 2; 5497117f1b4Smrg } 5507117f1b4Smrg if (i >= minLevel && i <= maxLevel) { 5517117f1b4Smrg if (!t->Image[0][i]) { 5527117f1b4Smrg incomplete(t, "1D Image[0][i] == NULL"); 5537117f1b4Smrg return; 5547117f1b4Smrg } 5557117f1b4Smrg if (t->Image[0][i]->Width2 != width ) { 5567117f1b4Smrg incomplete(t, "1D Image[0][i] bad width"); 5577117f1b4Smrg return; 5587117f1b4Smrg } 5597117f1b4Smrg } 5607117f1b4Smrg if (width == 1) { 5617117f1b4Smrg return; /* found smallest needed mipmap, all done! */ 5627117f1b4Smrg } 5637117f1b4Smrg } 5647117f1b4Smrg } 565c1f859d4Smrg else if ((t->Target == GL_TEXTURE_2D) || 566c1f859d4Smrg (t->Target == GL_TEXTURE_2D_ARRAY_EXT)) { 5677117f1b4Smrg /* Test 2-D mipmaps */ 5687117f1b4Smrg GLuint width = t->Image[0][baseLevel]->Width2; 5697117f1b4Smrg GLuint height = t->Image[0][baseLevel]->Height2; 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 (i >= minLevel && i <= maxLevel) { 5787117f1b4Smrg if (!t->Image[0][i]) { 5797117f1b4Smrg incomplete(t, "2D Image[0][i] == NULL"); 5807117f1b4Smrg return; 5817117f1b4Smrg } 5827117f1b4Smrg if (t->Image[0][i]->Width2 != width) { 5837117f1b4Smrg incomplete(t, "2D Image[0][i] bad width"); 5847117f1b4Smrg return; 5857117f1b4Smrg } 5867117f1b4Smrg if (t->Image[0][i]->Height2 != height) { 5877117f1b4Smrg incomplete(t, "2D Image[0][i] bad height"); 5887117f1b4Smrg return; 5897117f1b4Smrg } 5907117f1b4Smrg if (width==1 && height==1) { 5917117f1b4Smrg return; /* found smallest needed mipmap, all done! */ 5927117f1b4Smrg } 5937117f1b4Smrg } 5947117f1b4Smrg } 5957117f1b4Smrg } 5967117f1b4Smrg else if (t->Target == GL_TEXTURE_3D) { 5977117f1b4Smrg /* Test 3-D mipmaps */ 5987117f1b4Smrg GLuint width = t->Image[0][baseLevel]->Width2; 5997117f1b4Smrg GLuint height = t->Image[0][baseLevel]->Height2; 6007117f1b4Smrg GLuint depth = t->Image[0][baseLevel]->Depth2; 6013464ebd5Sriastradh for (i = baseLevel + 1; i < maxLevels; i++) { 6027117f1b4Smrg if (width > 1) { 6037117f1b4Smrg width /= 2; 6047117f1b4Smrg } 6057117f1b4Smrg if (height > 1) { 6067117f1b4Smrg height /= 2; 6077117f1b4Smrg } 6087117f1b4Smrg if (depth > 1) { 6097117f1b4Smrg depth /= 2; 6107117f1b4Smrg } 6117117f1b4Smrg if (i >= minLevel && i <= maxLevel) { 6127117f1b4Smrg if (!t->Image[0][i]) { 6137117f1b4Smrg incomplete(t, "3D Image[0][i] == NULL"); 6147117f1b4Smrg return; 6157117f1b4Smrg } 6167117f1b4Smrg if (t->Image[0][i]->_BaseFormat == GL_DEPTH_COMPONENT) { 6177117f1b4Smrg incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex"); 6187117f1b4Smrg return; 6197117f1b4Smrg } 6207117f1b4Smrg if (t->Image[0][i]->Width2 != width) { 6217117f1b4Smrg incomplete(t, "3D Image[0][i] bad width"); 6227117f1b4Smrg return; 6237117f1b4Smrg } 6247117f1b4Smrg if (t->Image[0][i]->Height2 != height) { 6257117f1b4Smrg incomplete(t, "3D Image[0][i] bad height"); 6267117f1b4Smrg return; 6277117f1b4Smrg } 6287117f1b4Smrg if (t->Image[0][i]->Depth2 != depth) { 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; 6423464ebd5Sriastradh 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]) { 6547117f1b4Smrg incomplete(t, "CubeMap Image[n][i] == NULL"); 6557117f1b4Smrg return; 6567117f1b4Smrg } 6577117f1b4Smrg /* Don't support GL_DEPTH_COMPONENT for cube maps */ 6587117f1b4Smrg if (t->Image[face][i]->_BaseFormat == GL_DEPTH_COMPONENT) { 6597117f1b4Smrg incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex"); 6607117f1b4Smrg return; 6617117f1b4Smrg } 6627117f1b4Smrg /* check that all six images have same size */ 6633464ebd5Sriastradh if (t->Image[face][i]->Width2 != width || 6643464ebd5Sriastradh t->Image[face][i]->Height2 != height) { 6657117f1b4Smrg incomplete(t, "CubeMap Image[n][i] bad size"); 6667117f1b4Smrg return; 6677117f1b4Smrg } 6687117f1b4Smrg } 6697117f1b4Smrg } 6707117f1b4Smrg if (width == 1 && height == 1) { 6717117f1b4Smrg return; /* found smallest needed mipmap, all done! */ 6727117f1b4Smrg } 6737117f1b4Smrg } 6747117f1b4Smrg } 6757117f1b4Smrg else if (t->Target == GL_TEXTURE_RECTANGLE_NV) { 6767117f1b4Smrg /* XXX special checking? */ 6777117f1b4Smrg } 6787117f1b4Smrg else { 6797117f1b4Smrg /* Target = ??? */ 6807117f1b4Smrg _mesa_problem(ctx, "Bug in gl_test_texture_object_completeness\n"); 6817117f1b4Smrg } 6827117f1b4Smrg } 6837117f1b4Smrg} 6847117f1b4Smrg 6854a49301eSmrg 6863464ebd5Sriastradh/** 6873464ebd5Sriastradh * Check if the given cube map texture is "cube complete" as defined in 6883464ebd5Sriastradh * the OpenGL specification. 6893464ebd5Sriastradh */ 6903464ebd5SriastradhGLboolean 6913464ebd5Sriastradh_mesa_cube_complete(const struct gl_texture_object *texObj) 6923464ebd5Sriastradh{ 6933464ebd5Sriastradh const GLint baseLevel = texObj->BaseLevel; 6943464ebd5Sriastradh const struct gl_texture_image *img0, *img; 6953464ebd5Sriastradh GLuint face; 6963464ebd5Sriastradh 6973464ebd5Sriastradh if (texObj->Target != GL_TEXTURE_CUBE_MAP) 6983464ebd5Sriastradh return GL_FALSE; 6993464ebd5Sriastradh 7003464ebd5Sriastradh if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS)) 7013464ebd5Sriastradh return GL_FALSE; 7023464ebd5Sriastradh 7033464ebd5Sriastradh /* check first face */ 7043464ebd5Sriastradh img0 = texObj->Image[0][baseLevel]; 7053464ebd5Sriastradh if (!img0 || 7063464ebd5Sriastradh img0->Width < 1 || 7073464ebd5Sriastradh img0->Width != img0->Height) 7083464ebd5Sriastradh return GL_FALSE; 7093464ebd5Sriastradh 7103464ebd5Sriastradh /* check remaining faces vs. first face */ 7113464ebd5Sriastradh for (face = 1; face < 6; face++) { 7123464ebd5Sriastradh img = texObj->Image[face][baseLevel]; 7133464ebd5Sriastradh if (!img || 7143464ebd5Sriastradh img->Width != img0->Width || 7153464ebd5Sriastradh img->Height != img0->Height || 7163464ebd5Sriastradh img->TexFormat != img0->TexFormat) 7173464ebd5Sriastradh return GL_FALSE; 7183464ebd5Sriastradh } 7193464ebd5Sriastradh 7203464ebd5Sriastradh return GL_TRUE; 7213464ebd5Sriastradh} 7223464ebd5Sriastradh 7233464ebd5Sriastradh 7244a49301eSmrg/** 7254a49301eSmrg * Mark a texture object dirty. It forces the object to be incomplete 7264a49301eSmrg * and optionally forces the context to re-validate its state. 7274a49301eSmrg * 7284a49301eSmrg * \param ctx GL context. 7294a49301eSmrg * \param texObj texture object. 7304a49301eSmrg * \param invalidate_state also invalidate context state. 7314a49301eSmrg */ 7324a49301eSmrgvoid 7333464ebd5Sriastradh_mesa_dirty_texobj(struct gl_context *ctx, struct gl_texture_object *texObj, 7344a49301eSmrg GLboolean invalidate_state) 7354a49301eSmrg{ 7364a49301eSmrg texObj->_Complete = GL_FALSE; 7374a49301eSmrg if (invalidate_state) 7384a49301eSmrg ctx->NewState |= _NEW_TEXTURE; 7394a49301eSmrg} 7404a49301eSmrg 7414a49301eSmrg 7424a49301eSmrg/** 7434a49301eSmrg * Return pointer to a default/fallback texture. 7444a49301eSmrg * The texture is a 2D 8x8 RGBA texture with all texels = (0,0,0,1). 7454a49301eSmrg * That's the value a sampler should get when sampling from an 7464a49301eSmrg * incomplete texture. 7474a49301eSmrg */ 7484a49301eSmrgstruct gl_texture_object * 7493464ebd5Sriastradh_mesa_get_fallback_texture(struct gl_context *ctx) 7504a49301eSmrg{ 7514a49301eSmrg if (!ctx->Shared->FallbackTex) { 7524a49301eSmrg /* create fallback texture now */ 7534a49301eSmrg static GLubyte texels[8 * 8][4]; 7544a49301eSmrg struct gl_texture_object *texObj; 7554a49301eSmrg struct gl_texture_image *texImage; 7563464ebd5Sriastradh gl_format texFormat; 7574a49301eSmrg GLuint i; 7584a49301eSmrg 7594a49301eSmrg for (i = 0; i < 8 * 8; i++) { 7604a49301eSmrg texels[i][0] = 7614a49301eSmrg texels[i][1] = 7624a49301eSmrg texels[i][2] = 0x0; 7634a49301eSmrg texels[i][3] = 0xff; 7644a49301eSmrg } 7654a49301eSmrg 7664a49301eSmrg /* create texture object */ 7674a49301eSmrg texObj = ctx->Driver.NewTextureObject(ctx, 0, GL_TEXTURE_2D); 7684a49301eSmrg assert(texObj->RefCount == 1); 7693464ebd5Sriastradh texObj->Sampler.MinFilter = GL_NEAREST; 7703464ebd5Sriastradh texObj->Sampler.MagFilter = GL_NEAREST; 7714a49301eSmrg 7724a49301eSmrg /* create level[0] texture image */ 7734a49301eSmrg texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, 0); 7744a49301eSmrg 7753464ebd5Sriastradh texFormat = ctx->Driver.ChooseTextureFormat(ctx, GL_RGBA, GL_RGBA, 7763464ebd5Sriastradh GL_UNSIGNED_BYTE); 7773464ebd5Sriastradh 7784a49301eSmrg /* init the image fields */ 7794a49301eSmrg _mesa_init_teximage_fields(ctx, GL_TEXTURE_2D, texImage, 7803464ebd5Sriastradh 8, 8, 1, 0, GL_RGBA, texFormat); 7814a49301eSmrg 7824a49301eSmrg ASSERT(texImage->TexFormat != MESA_FORMAT_NONE); 7834a49301eSmrg 7844a49301eSmrg /* set image data */ 7854a49301eSmrg ctx->Driver.TexImage2D(ctx, GL_TEXTURE_2D, 0, GL_RGBA, 7864a49301eSmrg 8, 8, 0, 7874a49301eSmrg GL_RGBA, GL_UNSIGNED_BYTE, texels, 7884a49301eSmrg &ctx->DefaultPacking, texObj, texImage); 7894a49301eSmrg 7904a49301eSmrg _mesa_test_texobj_completeness(ctx, texObj); 7914a49301eSmrg assert(texObj->_Complete); 7924a49301eSmrg 7934a49301eSmrg ctx->Shared->FallbackTex = texObj; 7944a49301eSmrg } 7954a49301eSmrg return ctx->Shared->FallbackTex; 7964a49301eSmrg} 7974a49301eSmrg 7984a49301eSmrg 7997117f1b4Smrg/*@}*/ 8007117f1b4Smrg 8017117f1b4Smrg 8027117f1b4Smrg/***********************************************************************/ 8037117f1b4Smrg/** \name API functions */ 8047117f1b4Smrg/*@{*/ 8057117f1b4Smrg 8067117f1b4Smrg 8077117f1b4Smrg/** 8087117f1b4Smrg * Generate texture names. 8097117f1b4Smrg * 8107117f1b4Smrg * \param n number of texture names to be generated. 8117117f1b4Smrg * \param textures an array in which will hold the generated texture names. 8127117f1b4Smrg * 8137117f1b4Smrg * \sa glGenTextures(). 8147117f1b4Smrg * 815c1f859d4Smrg * Calls _mesa_HashFindFreeKeyBlock() to find a block of free texture 816c1f859d4Smrg * IDs which are stored in \p textures. Corresponding empty texture 817c1f859d4Smrg * objects are also generated. 8187117f1b4Smrg */ 8197117f1b4Smrgvoid GLAPIENTRY 8207117f1b4Smrg_mesa_GenTextures( GLsizei n, GLuint *textures ) 8217117f1b4Smrg{ 8227117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 8237117f1b4Smrg GLuint first; 8247117f1b4Smrg GLint i; 8257117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 8267117f1b4Smrg 8277117f1b4Smrg if (n < 0) { 8287117f1b4Smrg _mesa_error( ctx, GL_INVALID_VALUE, "glGenTextures" ); 8297117f1b4Smrg return; 8307117f1b4Smrg } 8317117f1b4Smrg 8327117f1b4Smrg if (!textures) 8337117f1b4Smrg return; 8347117f1b4Smrg 8357117f1b4Smrg /* 8367117f1b4Smrg * This must be atomic (generation and allocation of texture IDs) 8377117f1b4Smrg */ 838c1f859d4Smrg _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 8397117f1b4Smrg 8407117f1b4Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Shared->TexObjects, n); 8417117f1b4Smrg 8427117f1b4Smrg /* Allocate new, empty texture objects */ 8437117f1b4Smrg for (i = 0; i < n; i++) { 8447117f1b4Smrg struct gl_texture_object *texObj; 8457117f1b4Smrg GLuint name = first + i; 8467117f1b4Smrg GLenum target = 0; 8477117f1b4Smrg texObj = (*ctx->Driver.NewTextureObject)( ctx, name, target); 8487117f1b4Smrg if (!texObj) { 849c1f859d4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 8507117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures"); 8517117f1b4Smrg return; 8527117f1b4Smrg } 8537117f1b4Smrg 8547117f1b4Smrg /* insert into hash table */ 8557117f1b4Smrg _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj); 8567117f1b4Smrg 8577117f1b4Smrg textures[i] = name; 8587117f1b4Smrg } 8597117f1b4Smrg 860c1f859d4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 8617117f1b4Smrg} 8627117f1b4Smrg 8637117f1b4Smrg 8647117f1b4Smrg/** 8657117f1b4Smrg * Check if the given texture object is bound to the current draw or 8667117f1b4Smrg * read framebuffer. If so, Unbind it. 8677117f1b4Smrg */ 8687117f1b4Smrgstatic void 8693464ebd5Sriastradhunbind_texobj_from_fbo(struct gl_context *ctx, 8703464ebd5Sriastradh struct gl_texture_object *texObj) 8717117f1b4Smrg{ 8727117f1b4Smrg const GLuint n = (ctx->DrawBuffer == ctx->ReadBuffer) ? 1 : 2; 8737117f1b4Smrg GLuint i; 8747117f1b4Smrg 8757117f1b4Smrg for (i = 0; i < n; i++) { 8767117f1b4Smrg struct gl_framebuffer *fb = (i == 0) ? ctx->DrawBuffer : ctx->ReadBuffer; 8777117f1b4Smrg if (fb->Name) { 8787117f1b4Smrg GLuint j; 8797117f1b4Smrg for (j = 0; j < BUFFER_COUNT; j++) { 8807117f1b4Smrg if (fb->Attachment[j].Type == GL_TEXTURE && 8817117f1b4Smrg fb->Attachment[j].Texture == texObj) { 8823464ebd5Sriastradh /* Vertices are already flushed by _mesa_DeleteTextures */ 8833464ebd5Sriastradh ctx->NewState |= _NEW_BUFFERS; 8847117f1b4Smrg _mesa_remove_attachment(ctx, fb->Attachment + j); 8857117f1b4Smrg } 8867117f1b4Smrg } 8877117f1b4Smrg } 8887117f1b4Smrg } 8897117f1b4Smrg} 8907117f1b4Smrg 8917117f1b4Smrg 8927117f1b4Smrg/** 8937117f1b4Smrg * Check if the given texture object is bound to any texture image units and 8947117f1b4Smrg * unbind it if so (revert to default textures). 8957117f1b4Smrg */ 8967117f1b4Smrgstatic void 8973464ebd5Sriastradhunbind_texobj_from_texunits(struct gl_context *ctx, 8983464ebd5Sriastradh struct gl_texture_object *texObj) 8997117f1b4Smrg{ 900c1f859d4Smrg GLuint u, tex; 9017117f1b4Smrg 9023464ebd5Sriastradh for (u = 0; u < Elements(ctx->Texture.Unit); u++) { 9037117f1b4Smrg struct gl_texture_unit *unit = &ctx->Texture.Unit[u]; 904c1f859d4Smrg for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) { 905c1f859d4Smrg if (texObj == unit->CurrentTex[tex]) { 906c1f859d4Smrg _mesa_reference_texobj(&unit->CurrentTex[tex], 9074a49301eSmrg ctx->Shared->DefaultTex[tex]); 908c1f859d4Smrg ASSERT(unit->CurrentTex[tex]); 909c1f859d4Smrg break; 910c1f859d4Smrg } 9117117f1b4Smrg } 9127117f1b4Smrg } 9137117f1b4Smrg} 9147117f1b4Smrg 9157117f1b4Smrg 9167117f1b4Smrg/** 9177117f1b4Smrg * Delete named textures. 9187117f1b4Smrg * 9197117f1b4Smrg * \param n number of textures to be deleted. 9207117f1b4Smrg * \param textures array of texture IDs to be deleted. 9217117f1b4Smrg * 9227117f1b4Smrg * \sa glDeleteTextures(). 9237117f1b4Smrg * 9247117f1b4Smrg * If we're about to delete a texture that's currently bound to any 9257117f1b4Smrg * texture unit, unbind the texture first. Decrement the reference 9267117f1b4Smrg * count on the texture object and delete it if it's zero. 9277117f1b4Smrg * Recall that texture objects can be shared among several rendering 9287117f1b4Smrg * contexts. 9297117f1b4Smrg */ 9307117f1b4Smrgvoid GLAPIENTRY 9317117f1b4Smrg_mesa_DeleteTextures( GLsizei n, const GLuint *textures) 9327117f1b4Smrg{ 9337117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 9347117f1b4Smrg GLint i; 9357117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */ 9367117f1b4Smrg 9377117f1b4Smrg if (!textures) 9387117f1b4Smrg return; 9397117f1b4Smrg 9407117f1b4Smrg for (i = 0; i < n; i++) { 9417117f1b4Smrg if (textures[i] > 0) { 9427117f1b4Smrg struct gl_texture_object *delObj 9437117f1b4Smrg = _mesa_lookup_texture(ctx, textures[i]); 9447117f1b4Smrg 9457117f1b4Smrg if (delObj) { 9463464ebd5Sriastradh _mesa_lock_texture(ctx, delObj); 9477117f1b4Smrg 9487117f1b4Smrg /* Check if texture is bound to any framebuffer objects. 9497117f1b4Smrg * If so, unbind. 9507117f1b4Smrg * See section 4.4.2.3 of GL_EXT_framebuffer_object. 9517117f1b4Smrg */ 9527117f1b4Smrg unbind_texobj_from_fbo(ctx, delObj); 9537117f1b4Smrg 9547117f1b4Smrg /* Check if this texture is currently bound to any texture units. 9557117f1b4Smrg * If so, unbind it. 9567117f1b4Smrg */ 9577117f1b4Smrg unbind_texobj_from_texunits(ctx, delObj); 9587117f1b4Smrg 9593464ebd5Sriastradh _mesa_unlock_texture(ctx, delObj); 9607117f1b4Smrg 9617117f1b4Smrg ctx->NewState |= _NEW_TEXTURE; 9627117f1b4Smrg 9637117f1b4Smrg /* The texture _name_ is now free for re-use. 9647117f1b4Smrg * Remove it from the hash table now. 9657117f1b4Smrg */ 9667117f1b4Smrg _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 9677117f1b4Smrg _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name); 9687117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 9697117f1b4Smrg 9707117f1b4Smrg /* Unreference the texobj. If refcount hits zero, the texture 9717117f1b4Smrg * will be deleted. 9727117f1b4Smrg */ 9737117f1b4Smrg _mesa_reference_texobj(&delObj, NULL); 9747117f1b4Smrg } 9757117f1b4Smrg } 9767117f1b4Smrg } 9777117f1b4Smrg} 9787117f1b4Smrg 9797117f1b4Smrg 980c1f859d4Smrg/** 981c1f859d4Smrg * Convert a GL texture target enum such as GL_TEXTURE_2D or GL_TEXTURE_3D 982c1f859d4Smrg * into the corresponding Mesa texture target index. 983cdc920a0Smrg * Note that proxy targets are not valid here. 984cdc920a0Smrg * \return TEXTURE_x_INDEX or -1 if target is invalid 985c1f859d4Smrg */ 986c1f859d4Smrgstatic GLint 987c1f859d4Smrgtarget_enum_to_index(GLenum target) 988c1f859d4Smrg{ 989c1f859d4Smrg switch (target) { 990c1f859d4Smrg case GL_TEXTURE_1D: 991c1f859d4Smrg return TEXTURE_1D_INDEX; 992c1f859d4Smrg case GL_TEXTURE_2D: 993c1f859d4Smrg return TEXTURE_2D_INDEX; 994c1f859d4Smrg case GL_TEXTURE_3D: 995c1f859d4Smrg return TEXTURE_3D_INDEX; 996c1f859d4Smrg case GL_TEXTURE_CUBE_MAP_ARB: 997c1f859d4Smrg return TEXTURE_CUBE_INDEX; 998c1f859d4Smrg case GL_TEXTURE_RECTANGLE_NV: 999c1f859d4Smrg return TEXTURE_RECT_INDEX; 1000c1f859d4Smrg case GL_TEXTURE_1D_ARRAY_EXT: 1001c1f859d4Smrg return TEXTURE_1D_ARRAY_INDEX; 1002c1f859d4Smrg case GL_TEXTURE_2D_ARRAY_EXT: 1003c1f859d4Smrg return TEXTURE_2D_ARRAY_INDEX; 10043464ebd5Sriastradh case GL_TEXTURE_BUFFER_ARB: 10053464ebd5Sriastradh return TEXTURE_BUFFER_INDEX; 1006c1f859d4Smrg default: 1007c1f859d4Smrg return -1; 1008c1f859d4Smrg } 1009c1f859d4Smrg} 1010c1f859d4Smrg 1011c1f859d4Smrg 10127117f1b4Smrg/** 10137117f1b4Smrg * Bind a named texture to a texturing target. 10147117f1b4Smrg * 10157117f1b4Smrg * \param target texture target. 10167117f1b4Smrg * \param texName texture name. 10177117f1b4Smrg * 10187117f1b4Smrg * \sa glBindTexture(). 10197117f1b4Smrg * 10207117f1b4Smrg * Determines the old texture object bound and returns immediately if rebinding 10217117f1b4Smrg * the same texture. Get the current texture which is either a default texture 10227117f1b4Smrg * if name is null, a named texture from the hash, or a new texture if the 10237117f1b4Smrg * given texture name is new. Increments its reference count, binds it, and 10247117f1b4Smrg * calls dd_function_table::BindTexture. Decrements the old texture reference 10257117f1b4Smrg * count and deletes it if it reaches zero. 10267117f1b4Smrg */ 10277117f1b4Smrgvoid GLAPIENTRY 10287117f1b4Smrg_mesa_BindTexture( GLenum target, GLuint texName ) 10297117f1b4Smrg{ 10307117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 10313464ebd5Sriastradh struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); 10323464ebd5Sriastradh struct gl_texture_object *newTexObj = NULL; 1033c1f859d4Smrg GLint targetIndex; 10347117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END(ctx); 10357117f1b4Smrg 10367117f1b4Smrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 10377117f1b4Smrg _mesa_debug(ctx, "glBindTexture %s %d\n", 10387117f1b4Smrg _mesa_lookup_enum_by_nr(target), (GLint) texName); 10397117f1b4Smrg 1040c1f859d4Smrg targetIndex = target_enum_to_index(target); 1041c1f859d4Smrg if (targetIndex < 0) { 1042c1f859d4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)"); 1043c1f859d4Smrg return; 1044c1f859d4Smrg } 1045c1f859d4Smrg assert(targetIndex < NUM_TEXTURE_TARGETS); 1046c1f859d4Smrg 10477117f1b4Smrg /* 10487117f1b4Smrg * Get pointer to new texture object (newTexObj) 10497117f1b4Smrg */ 10507117f1b4Smrg if (texName == 0) { 10513464ebd5Sriastradh /* Use a default texture object */ 10523464ebd5Sriastradh newTexObj = ctx->Shared->DefaultTex[targetIndex]; 10537117f1b4Smrg } 10547117f1b4Smrg else { 10557117f1b4Smrg /* non-default texture object */ 10567117f1b4Smrg newTexObj = _mesa_lookup_texture(ctx, texName); 10577117f1b4Smrg if (newTexObj) { 10587117f1b4Smrg /* error checking */ 10597117f1b4Smrg if (newTexObj->Target != 0 && newTexObj->Target != target) { 1060c1f859d4Smrg /* the named texture object's target doesn't match the given target */ 10617117f1b4Smrg _mesa_error( ctx, GL_INVALID_OPERATION, 1062c1f859d4Smrg "glBindTexture(target mismatch)" ); 10637117f1b4Smrg return; 10647117f1b4Smrg } 1065c1f859d4Smrg if (newTexObj->Target == 0) { 1066c1f859d4Smrg finish_texture_init(ctx, target, newTexObj); 10677117f1b4Smrg } 10687117f1b4Smrg } 10697117f1b4Smrg else { 10707117f1b4Smrg /* if this is a new texture id, allocate a texture object now */ 10713464ebd5Sriastradh newTexObj = (*ctx->Driver.NewTextureObject)(ctx, texName, target); 10727117f1b4Smrg if (!newTexObj) { 10737117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture"); 10747117f1b4Smrg return; 10757117f1b4Smrg } 10767117f1b4Smrg 10777117f1b4Smrg /* and insert it into hash table */ 10787117f1b4Smrg _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 10797117f1b4Smrg _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj); 10807117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 10817117f1b4Smrg } 10827117f1b4Smrg newTexObj->Target = target; 10837117f1b4Smrg } 10847117f1b4Smrg 10857117f1b4Smrg assert(valid_texture_object(newTexObj)); 10867117f1b4Smrg 10873464ebd5Sriastradh /* Check if this texture is only used by this context and is already bound. 10883464ebd5Sriastradh * If so, just return. 10893464ebd5Sriastradh */ 10903464ebd5Sriastradh { 10913464ebd5Sriastradh GLboolean early_out; 10923464ebd5Sriastradh _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 10933464ebd5Sriastradh early_out = ((ctx->Shared->RefCount == 1) 10943464ebd5Sriastradh && (newTexObj == texUnit->CurrentTex[targetIndex])); 10953464ebd5Sriastradh _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 10963464ebd5Sriastradh if (early_out) { 10973464ebd5Sriastradh return; 10983464ebd5Sriastradh } 10994a49301eSmrg } 11004a49301eSmrg 11017117f1b4Smrg /* flush before changing binding */ 11027117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_TEXTURE); 11037117f1b4Smrg 11047117f1b4Smrg /* Do the actual binding. The refcount on the previously bound 11057117f1b4Smrg * texture object will be decremented. It'll be deleted if the 11067117f1b4Smrg * count hits zero. 11077117f1b4Smrg */ 1108c1f859d4Smrg _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], newTexObj); 1109c1f859d4Smrg ASSERT(texUnit->CurrentTex[targetIndex]); 11107117f1b4Smrg 11117117f1b4Smrg /* Pass BindTexture call to device driver */ 11127117f1b4Smrg if (ctx->Driver.BindTexture) 11137117f1b4Smrg (*ctx->Driver.BindTexture)( ctx, target, newTexObj ); 11147117f1b4Smrg} 11157117f1b4Smrg 11167117f1b4Smrg 11177117f1b4Smrg/** 11187117f1b4Smrg * Set texture priorities. 11197117f1b4Smrg * 11207117f1b4Smrg * \param n number of textures. 11217117f1b4Smrg * \param texName texture names. 11227117f1b4Smrg * \param priorities corresponding texture priorities. 11237117f1b4Smrg * 11247117f1b4Smrg * \sa glPrioritizeTextures(). 11257117f1b4Smrg * 11267117f1b4Smrg * Looks up each texture in the hash, clamps the corresponding priority between 11277117f1b4Smrg * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture. 11287117f1b4Smrg */ 11297117f1b4Smrgvoid GLAPIENTRY 11307117f1b4Smrg_mesa_PrioritizeTextures( GLsizei n, const GLuint *texName, 11317117f1b4Smrg const GLclampf *priorities ) 11327117f1b4Smrg{ 11337117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 11347117f1b4Smrg GLint i; 11357117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 11367117f1b4Smrg 11377117f1b4Smrg if (n < 0) { 11387117f1b4Smrg _mesa_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" ); 11397117f1b4Smrg return; 11407117f1b4Smrg } 11417117f1b4Smrg 11427117f1b4Smrg if (!priorities) 11437117f1b4Smrg return; 11447117f1b4Smrg 11457117f1b4Smrg for (i = 0; i < n; i++) { 11467117f1b4Smrg if (texName[i] > 0) { 11477117f1b4Smrg struct gl_texture_object *t = _mesa_lookup_texture(ctx, texName[i]); 11487117f1b4Smrg if (t) { 11497117f1b4Smrg t->Priority = CLAMP( priorities[i], 0.0F, 1.0F ); 11507117f1b4Smrg } 11517117f1b4Smrg } 11527117f1b4Smrg } 11537117f1b4Smrg 11547117f1b4Smrg ctx->NewState |= _NEW_TEXTURE; 11557117f1b4Smrg} 11567117f1b4Smrg 11573464ebd5Sriastradh 11583464ebd5Sriastradh 11597117f1b4Smrg/** 11607117f1b4Smrg * See if textures are loaded in texture memory. 11617117f1b4Smrg * 11627117f1b4Smrg * \param n number of textures to query. 11637117f1b4Smrg * \param texName array with the texture names. 11647117f1b4Smrg * \param residences array which will hold the residence status. 11657117f1b4Smrg * 11667117f1b4Smrg * \return GL_TRUE if all textures are resident and \p residences is left unchanged, 11677117f1b4Smrg * 11687117f1b4Smrg * \sa glAreTexturesResident(). 11697117f1b4Smrg * 11707117f1b4Smrg * Looks up each texture in the hash and calls 11717117f1b4Smrg * dd_function_table::IsTextureResident. 11727117f1b4Smrg */ 11737117f1b4SmrgGLboolean GLAPIENTRY 11747117f1b4Smrg_mesa_AreTexturesResident(GLsizei n, const GLuint *texName, 11757117f1b4Smrg GLboolean *residences) 11767117f1b4Smrg{ 11777117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 11787117f1b4Smrg GLboolean allResident = GL_TRUE; 11797117f1b4Smrg GLint i, j; 11807117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 11817117f1b4Smrg 11827117f1b4Smrg if (n < 0) { 11837117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)"); 11847117f1b4Smrg return GL_FALSE; 11857117f1b4Smrg } 11867117f1b4Smrg 11877117f1b4Smrg if (!texName || !residences) 11887117f1b4Smrg return GL_FALSE; 11897117f1b4Smrg 11907117f1b4Smrg for (i = 0; i < n; i++) { 11917117f1b4Smrg struct gl_texture_object *t; 11927117f1b4Smrg if (texName[i] == 0) { 11937117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident"); 11947117f1b4Smrg return GL_FALSE; 11957117f1b4Smrg } 11967117f1b4Smrg t = _mesa_lookup_texture(ctx, texName[i]); 11977117f1b4Smrg if (!t) { 11987117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident"); 11997117f1b4Smrg return GL_FALSE; 12007117f1b4Smrg } 12017117f1b4Smrg if (!ctx->Driver.IsTextureResident || 12027117f1b4Smrg ctx->Driver.IsTextureResident(ctx, t)) { 12037117f1b4Smrg /* The texture is resident */ 12043464ebd5Sriastradh if (!allResident) 12053464ebd5Sriastradh residences[i] = GL_TRUE; 12067117f1b4Smrg } 12077117f1b4Smrg else { 12087117f1b4Smrg /* The texture is not resident */ 12097117f1b4Smrg if (allResident) { 12103464ebd5Sriastradh allResident = GL_FALSE; 12113464ebd5Sriastradh for (j = 0; j < i; j++) 12123464ebd5Sriastradh residences[j] = GL_TRUE; 12133464ebd5Sriastradh } 12143464ebd5Sriastradh residences[i] = GL_FALSE; 12157117f1b4Smrg } 12167117f1b4Smrg } 12177117f1b4Smrg 12187117f1b4Smrg return allResident; 12197117f1b4Smrg} 12207117f1b4Smrg 12213464ebd5Sriastradh 12227117f1b4Smrg/** 12237117f1b4Smrg * See if a name corresponds to a texture. 12247117f1b4Smrg * 12257117f1b4Smrg * \param texture texture name. 12267117f1b4Smrg * 12277117f1b4Smrg * \return GL_TRUE if texture name corresponds to a texture, or GL_FALSE 12287117f1b4Smrg * otherwise. 12297117f1b4Smrg * 12307117f1b4Smrg * \sa glIsTexture(). 12317117f1b4Smrg * 12327117f1b4Smrg * Calls _mesa_HashLookup(). 12337117f1b4Smrg */ 12347117f1b4SmrgGLboolean GLAPIENTRY 12357117f1b4Smrg_mesa_IsTexture( GLuint texture ) 12367117f1b4Smrg{ 12377117f1b4Smrg struct gl_texture_object *t; 12387117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 12397117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 12407117f1b4Smrg 12417117f1b4Smrg if (!texture) 12427117f1b4Smrg return GL_FALSE; 12437117f1b4Smrg 12447117f1b4Smrg t = _mesa_lookup_texture(ctx, texture); 12457117f1b4Smrg 12467117f1b4Smrg /* IsTexture is true only after object has been bound once. */ 12477117f1b4Smrg return t && t->Target; 12487117f1b4Smrg} 12497117f1b4Smrg 1250c1f859d4Smrg 1251c1f859d4Smrg/** 12524a49301eSmrg * Simplest implementation of texture locking: grab the shared tex 12534a49301eSmrg * mutex. Examine the shared context state timestamp and if there has 12544a49301eSmrg * been a change, set the appropriate bits in ctx->NewState. 12557117f1b4Smrg * 1256c1f859d4Smrg * This is used to deal with synchronizing things when a texture object 1257c1f859d4Smrg * is used/modified by different contexts (or threads) which are sharing 1258c1f859d4Smrg * the texture. 1259c1f859d4Smrg * 1260c1f859d4Smrg * See also _mesa_lock/unlock_texture() in teximage.h 12617117f1b4Smrg */ 1262c1f859d4Smrgvoid 12633464ebd5Sriastradh_mesa_lock_context_textures( struct gl_context *ctx ) 12647117f1b4Smrg{ 12657117f1b4Smrg _glthread_LOCK_MUTEX(ctx->Shared->TexMutex); 12667117f1b4Smrg 12677117f1b4Smrg if (ctx->Shared->TextureStateStamp != ctx->TextureStateTimestamp) { 12687117f1b4Smrg ctx->NewState |= _NEW_TEXTURE; 12697117f1b4Smrg ctx->TextureStateTimestamp = ctx->Shared->TextureStateStamp; 12707117f1b4Smrg } 12717117f1b4Smrg} 12727117f1b4Smrg 12737117f1b4Smrg 1274c1f859d4Smrgvoid 12753464ebd5Sriastradh_mesa_unlock_context_textures( struct gl_context *ctx ) 12767117f1b4Smrg{ 12777117f1b4Smrg assert(ctx->Shared->TextureStateStamp == ctx->TextureStateTimestamp); 12787117f1b4Smrg _glthread_UNLOCK_MUTEX(ctx->Shared->TexMutex); 12797117f1b4Smrg} 12807117f1b4Smrg 12817117f1b4Smrg/*@}*/ 1282