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