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