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