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