texobj.c revision c1f859d4
1/**
2 * \file texobj.c
3 * Texture object management.
4 */
5
6/*
7 * Mesa 3-D graphics library
8 * Version:  7.1
9 *
10 * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
25 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
26 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 */
29
30
31#include "glheader.h"
32#if FEATURE_colortable
33#include "colortab.h"
34#endif
35#include "context.h"
36#include "enums.h"
37#include "fbobject.h"
38#include "hash.h"
39#include "imports.h"
40#include "macros.h"
41#include "teximage.h"
42#include "texstate.h"
43#include "texobj.h"
44#include "mtypes.h"
45
46
47/**********************************************************************/
48/** \name Internal functions */
49/*@{*/
50
51
52/**
53 * Return the gl_texture_object for a given ID.
54 */
55struct gl_texture_object *
56_mesa_lookup_texture(GLcontext *ctx, GLuint id)
57{
58   return (struct gl_texture_object *)
59      _mesa_HashLookup(ctx->Shared->TexObjects, id);
60}
61
62
63
64/**
65 * Allocate and initialize a new texture object.  But don't put it into the
66 * texture object hash table.
67 *
68 * Called via ctx->Driver.NewTextureObject, unless overridden by a device
69 * driver.
70 *
71 * \param shared the shared GL state structure to contain the texture object
72 * \param name integer name for the texture object
73 * \param target either GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D,
74 * GL_TEXTURE_CUBE_MAP_ARB or GL_TEXTURE_RECTANGLE_NV.  zero is ok for the sake
75 * of GenTextures()
76 *
77 * \return pointer to new texture object.
78 */
79struct gl_texture_object *
80_mesa_new_texture_object( GLcontext *ctx, GLuint name, GLenum target )
81{
82   struct gl_texture_object *obj;
83   (void) ctx;
84   obj = MALLOC_STRUCT(gl_texture_object);
85   _mesa_initialize_texture_object(obj, name, target);
86   return obj;
87}
88
89
90/**
91 * Initialize a new texture object to default values.
92 * \param obj  the texture object
93 * \param name  the texture name
94 * \param target  the texture target
95 */
96void
97_mesa_initialize_texture_object( struct gl_texture_object *obj,
98                                 GLuint name, GLenum target )
99{
100   ASSERT(target == 0 ||
101          target == GL_TEXTURE_1D ||
102          target == GL_TEXTURE_2D ||
103          target == GL_TEXTURE_3D ||
104          target == GL_TEXTURE_CUBE_MAP_ARB ||
105          target == GL_TEXTURE_RECTANGLE_NV ||
106          target == GL_TEXTURE_1D_ARRAY_EXT ||
107          target == GL_TEXTURE_2D_ARRAY_EXT);
108
109   _mesa_bzero(obj, sizeof(*obj));
110   /* init the non-zero fields */
111   _glthread_INIT_MUTEX(obj->Mutex);
112   obj->RefCount = 1;
113   obj->Name = name;
114   obj->Target = target;
115   obj->Priority = 1.0F;
116   if (target == GL_TEXTURE_RECTANGLE_NV) {
117      obj->WrapS = GL_CLAMP_TO_EDGE;
118      obj->WrapT = GL_CLAMP_TO_EDGE;
119      obj->WrapR = GL_CLAMP_TO_EDGE;
120      obj->MinFilter = GL_LINEAR;
121   }
122   else {
123      obj->WrapS = GL_REPEAT;
124      obj->WrapT = GL_REPEAT;
125      obj->WrapR = GL_REPEAT;
126      obj->MinFilter = GL_NEAREST_MIPMAP_LINEAR;
127   }
128   obj->MagFilter = GL_LINEAR;
129   obj->MinLod = -1000.0;
130   obj->MaxLod = 1000.0;
131   obj->LodBias = 0.0;
132   obj->BaseLevel = 0;
133   obj->MaxLevel = 1000;
134   obj->MaxAnisotropy = 1.0;
135   obj->CompareFlag = GL_FALSE;                      /* SGIX_shadow */
136   obj->CompareOperator = GL_TEXTURE_LEQUAL_R_SGIX;  /* SGIX_shadow */
137   obj->CompareMode = GL_NONE;         /* ARB_shadow */
138   obj->CompareFunc = GL_LEQUAL;       /* ARB_shadow */
139   obj->DepthMode = GL_LUMINANCE;      /* ARB_depth_texture */
140   obj->ShadowAmbient = 0.0F;          /* ARB/SGIX_shadow_ambient */
141}
142
143
144/**
145 * Some texture initialization can't be finished until we know which
146 * target it's getting bound to (GL_TEXTURE_1D/2D/etc).
147 */
148static void
149finish_texture_init(GLcontext *ctx, GLenum target,
150                    struct gl_texture_object *obj)
151{
152   assert(obj->Target == 0);
153
154   if (target == GL_TEXTURE_RECTANGLE_NV) {
155      /* have to init wrap and filter state here - kind of klunky */
156      obj->WrapS = GL_CLAMP_TO_EDGE;
157      obj->WrapT = GL_CLAMP_TO_EDGE;
158      obj->WrapR = GL_CLAMP_TO_EDGE;
159      obj->MinFilter = GL_LINEAR;
160      if (ctx->Driver.TexParameter) {
161         static const GLfloat fparam_wrap[1] = {(GLfloat) GL_CLAMP_TO_EDGE};
162         static const GLfloat fparam_filter[1] = {(GLfloat) GL_LINEAR};
163         ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_S, fparam_wrap);
164         ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_T, fparam_wrap);
165         ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_WRAP_R, fparam_wrap);
166         ctx->Driver.TexParameter(ctx, target, obj, GL_TEXTURE_MIN_FILTER, fparam_filter);
167      }
168   }
169}
170
171
172/**
173 * Deallocate a texture object struct.  It should have already been
174 * removed from the texture object pool.
175 * Called via ctx->Driver.DeleteTexture() if not overriden by a driver.
176 *
177 * \param shared the shared GL state to which the object belongs.
178 * \param texOjb the texture object to delete.
179 */
180void
181_mesa_delete_texture_object( GLcontext *ctx, struct gl_texture_object *texObj )
182{
183   GLuint i, face;
184
185   (void) ctx;
186
187   /* Set Target to an invalid value.  With some assertions elsewhere
188    * we can try to detect possible use of deleted textures.
189    */
190   texObj->Target = 0x99;
191
192#if FEATURE_colortable
193   _mesa_free_colortable_data(&texObj->Palette);
194#endif
195
196   /* free the texture images */
197   for (face = 0; face < 6; face++) {
198      for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
199	 if (texObj->Image[face][i]) {
200	    _mesa_delete_texture_image( ctx, texObj->Image[face][i] );
201	 }
202      }
203   }
204
205   /* destroy the mutex -- it may have allocated memory (eg on bsd) */
206   _glthread_DESTROY_MUTEX(texObj->Mutex);
207
208   /* free this object */
209   _mesa_free(texObj);
210}
211
212
213
214
215/**
216 * Copy texture object state from one texture object to another.
217 * Use for glPush/PopAttrib.
218 *
219 * \param dest destination texture object.
220 * \param src source texture object.
221 */
222void
223_mesa_copy_texture_object( struct gl_texture_object *dest,
224                           const struct gl_texture_object *src )
225{
226   dest->Target = src->Target;
227   dest->Name = src->Name;
228   dest->Priority = src->Priority;
229   dest->BorderColor[0] = src->BorderColor[0];
230   dest->BorderColor[1] = src->BorderColor[1];
231   dest->BorderColor[2] = src->BorderColor[2];
232   dest->BorderColor[3] = src->BorderColor[3];
233   dest->WrapS = src->WrapS;
234   dest->WrapT = src->WrapT;
235   dest->WrapR = src->WrapR;
236   dest->MinFilter = src->MinFilter;
237   dest->MagFilter = src->MagFilter;
238   dest->MinLod = src->MinLod;
239   dest->MaxLod = src->MaxLod;
240   dest->LodBias = src->LodBias;
241   dest->BaseLevel = src->BaseLevel;
242   dest->MaxLevel = src->MaxLevel;
243   dest->MaxAnisotropy = src->MaxAnisotropy;
244   dest->CompareFlag = src->CompareFlag;
245   dest->CompareOperator = src->CompareOperator;
246   dest->ShadowAmbient = src->ShadowAmbient;
247   dest->CompareMode = src->CompareMode;
248   dest->CompareFunc = src->CompareFunc;
249   dest->DepthMode = src->DepthMode;
250   dest->_MaxLevel = src->_MaxLevel;
251   dest->_MaxLambda = src->_MaxLambda;
252   dest->GenerateMipmap = src->GenerateMipmap;
253   dest->Palette = src->Palette;
254   dest->_Complete = src->_Complete;
255}
256
257
258/**
259 * Check if the given texture object is valid by examining its Target field.
260 * For debugging only.
261 */
262static GLboolean
263valid_texture_object(const struct gl_texture_object *tex)
264{
265   switch (tex->Target) {
266   case 0:
267   case GL_TEXTURE_1D:
268   case GL_TEXTURE_2D:
269   case GL_TEXTURE_3D:
270   case GL_TEXTURE_CUBE_MAP_ARB:
271   case GL_TEXTURE_RECTANGLE_NV:
272   case GL_TEXTURE_1D_ARRAY_EXT:
273   case GL_TEXTURE_2D_ARRAY_EXT:
274      return GL_TRUE;
275   case 0x99:
276      _mesa_problem(NULL, "invalid reference to a deleted texture object");
277      return GL_FALSE;
278   default:
279      _mesa_problem(NULL, "invalid texture object Target value");
280      return GL_FALSE;
281   }
282}
283
284
285/**
286 * Reference (or unreference) a texture object.
287 * If '*ptr', decrement *ptr's refcount (and delete if it becomes zero).
288 * If 'tex' is non-null, increment its refcount.
289 */
290void
291_mesa_reference_texobj(struct gl_texture_object **ptr,
292                       struct gl_texture_object *tex)
293{
294   assert(ptr);
295   if (*ptr == tex) {
296      /* no change */
297      return;
298   }
299
300   if (*ptr) {
301      /* Unreference the old texture */
302      GLboolean deleteFlag = GL_FALSE;
303      struct gl_texture_object *oldTex = *ptr;
304
305      assert(valid_texture_object(oldTex));
306
307      _glthread_LOCK_MUTEX(oldTex->Mutex);
308      ASSERT(oldTex->RefCount > 0);
309      oldTex->RefCount--;
310
311      deleteFlag = (oldTex->RefCount == 0);
312      _glthread_UNLOCK_MUTEX(oldTex->Mutex);
313
314      if (deleteFlag) {
315         GET_CURRENT_CONTEXT(ctx);
316         if (ctx)
317            ctx->Driver.DeleteTexture(ctx, oldTex);
318         else
319            _mesa_problem(NULL, "Unable to delete texture, no context");
320      }
321
322      *ptr = NULL;
323   }
324   assert(!*ptr);
325
326   if (tex) {
327      /* reference new texture */
328      assert(valid_texture_object(tex));
329      _glthread_LOCK_MUTEX(tex->Mutex);
330      if (tex->RefCount == 0) {
331         /* this texture's being deleted (look just above) */
332         /* Not sure this can every really happen.  Warn if it does. */
333         _mesa_problem(NULL, "referencing deleted texture object");
334         *ptr = NULL;
335      }
336      else {
337         tex->RefCount++;
338         *ptr = tex;
339      }
340      _glthread_UNLOCK_MUTEX(tex->Mutex);
341   }
342}
343
344
345
346/**
347 * Report why a texture object is incomplete.
348 *
349 * \param t texture object.
350 * \param why string describing why it's incomplete.
351 *
352 * \note For debug purposes only.
353 */
354#if 0
355static void
356incomplete(const struct gl_texture_object *t, const char *why)
357{
358   _mesa_printf("Texture Obj %d incomplete because: %s\n", t->Name, why);
359}
360#else
361#define incomplete(t, why)
362#endif
363
364
365/**
366 * Examine a texture object to determine if it is complete.
367 *
368 * The gl_texture_object::Complete flag will be set to GL_TRUE or GL_FALSE
369 * accordingly.
370 *
371 * \param ctx GL context.
372 * \param t texture object.
373 *
374 * According to the texture target, verifies that each of the mipmaps is
375 * present and has the expected size.
376 */
377void
378_mesa_test_texobj_completeness( const GLcontext *ctx,
379                                struct gl_texture_object *t )
380{
381   const GLint baseLevel = t->BaseLevel;
382   GLint maxLog2 = 0, maxLevels = 0;
383
384   t->_Complete = GL_TRUE;  /* be optimistic */
385
386   /* Detect cases where the application set the base level to an invalid
387    * value.
388    */
389   if ((baseLevel < 0) || (baseLevel > MAX_TEXTURE_LEVELS)) {
390      char s[100];
391      _mesa_sprintf(s, "obj %p (%d) base level = %d is invalid",
392              (void *) t, t->Name, baseLevel);
393      incomplete(t, s);
394      t->_Complete = GL_FALSE;
395      return;
396   }
397
398   /* Always need the base level image */
399   if (!t->Image[0][baseLevel]) {
400      char s[100];
401      _mesa_sprintf(s, "obj %p (%d) Image[baseLevel=%d] == NULL",
402              (void *) t, t->Name, baseLevel);
403      incomplete(t, s);
404      t->_Complete = GL_FALSE;
405      return;
406   }
407
408   /* Check width/height/depth for zero */
409   if (t->Image[0][baseLevel]->Width == 0 ||
410       t->Image[0][baseLevel]->Height == 0 ||
411       t->Image[0][baseLevel]->Depth == 0) {
412      incomplete(t, "texture width = 0");
413      t->_Complete = GL_FALSE;
414      return;
415   }
416
417   /* Compute _MaxLevel */
418   if ((t->Target == GL_TEXTURE_1D) ||
419       (t->Target == GL_TEXTURE_1D_ARRAY_EXT)) {
420      maxLog2 = t->Image[0][baseLevel]->WidthLog2;
421      maxLevels = ctx->Const.MaxTextureLevels;
422   }
423   else if ((t->Target == GL_TEXTURE_2D) ||
424	    (t->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
425      maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2,
426                     t->Image[0][baseLevel]->HeightLog2);
427      maxLevels = ctx->Const.MaxTextureLevels;
428   }
429   else if (t->Target == GL_TEXTURE_3D) {
430      GLint max = MAX2(t->Image[0][baseLevel]->WidthLog2,
431                       t->Image[0][baseLevel]->HeightLog2);
432      maxLog2 = MAX2(max, (GLint)(t->Image[0][baseLevel]->DepthLog2));
433      maxLevels = ctx->Const.Max3DTextureLevels;
434   }
435   else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
436      maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2,
437                     t->Image[0][baseLevel]->HeightLog2);
438      maxLevels = ctx->Const.MaxCubeTextureLevels;
439   }
440   else if (t->Target == GL_TEXTURE_RECTANGLE_NV) {
441      maxLog2 = 0;  /* not applicable */
442      maxLevels = 1;  /* no mipmapping */
443   }
444   else {
445      _mesa_problem(ctx, "Bad t->Target in _mesa_test_texobj_completeness");
446      return;
447   }
448
449   ASSERT(maxLevels > 0);
450
451   t->_MaxLevel = baseLevel + maxLog2;
452   t->_MaxLevel = MIN2(t->_MaxLevel, t->MaxLevel);
453   t->_MaxLevel = MIN2(t->_MaxLevel, maxLevels - 1);
454
455   /* Compute _MaxLambda = q - b (see the 1.2 spec) used during mipmapping */
456   t->_MaxLambda = (GLfloat) (t->_MaxLevel - t->BaseLevel);
457
458   if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
459      /* make sure that all six cube map level 0 images are the same size */
460      const GLuint w = t->Image[0][baseLevel]->Width2;
461      const GLuint h = t->Image[0][baseLevel]->Height2;
462      GLuint face;
463      for (face = 1; face < 6; face++) {
464	 if (t->Image[face][baseLevel] == NULL ||
465	     t->Image[face][baseLevel]->Width2 != w ||
466	     t->Image[face][baseLevel]->Height2 != h) {
467	    t->_Complete = GL_FALSE;
468	    incomplete(t, "Non-quare cubemap image");
469	    return;
470	 }
471      }
472   }
473
474   /* extra checking for mipmaps */
475   if (t->MinFilter != GL_NEAREST && t->MinFilter != GL_LINEAR) {
476      /*
477       * Mipmapping: determine if we have a complete set of mipmaps
478       */
479      GLint i;
480      GLint minLevel = baseLevel;
481      GLint maxLevel = t->_MaxLevel;
482
483      if (minLevel > maxLevel) {
484         t->_Complete = GL_FALSE;
485         incomplete(t, "minLevel > maxLevel");
486         return;
487      }
488
489      /* Test dimension-independent attributes */
490      for (i = minLevel; i <= maxLevel; i++) {
491         if (t->Image[0][i]) {
492            if (t->Image[0][i]->TexFormat != t->Image[0][baseLevel]->TexFormat) {
493               t->_Complete = GL_FALSE;
494               incomplete(t, "Format[i] != Format[baseLevel]");
495               return;
496            }
497            if (t->Image[0][i]->Border != t->Image[0][baseLevel]->Border) {
498               t->_Complete = GL_FALSE;
499               incomplete(t, "Border[i] != Border[baseLevel]");
500               return;
501            }
502         }
503      }
504
505      /* Test things which depend on number of texture image dimensions */
506      if ((t->Target == GL_TEXTURE_1D) ||
507          (t->Target == GL_TEXTURE_1D_ARRAY_EXT)) {
508         /* Test 1-D mipmaps */
509         GLuint width = t->Image[0][baseLevel]->Width2;
510         for (i = baseLevel + 1; i < maxLevels; i++) {
511            if (width > 1) {
512               width /= 2;
513            }
514            if (i >= minLevel && i <= maxLevel) {
515               if (!t->Image[0][i]) {
516                  t->_Complete = GL_FALSE;
517                  incomplete(t, "1D Image[0][i] == NULL");
518                  return;
519               }
520               if (t->Image[0][i]->Width2 != width ) {
521                  t->_Complete = GL_FALSE;
522                  incomplete(t, "1D Image[0][i] bad width");
523                  return;
524               }
525            }
526            if (width == 1) {
527               return;  /* found smallest needed mipmap, all done! */
528            }
529         }
530      }
531      else if ((t->Target == GL_TEXTURE_2D) ||
532               (t->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
533         /* Test 2-D mipmaps */
534         GLuint width = t->Image[0][baseLevel]->Width2;
535         GLuint height = t->Image[0][baseLevel]->Height2;
536         for (i = baseLevel + 1; i < maxLevels; i++) {
537            if (width > 1) {
538               width /= 2;
539            }
540            if (height > 1) {
541               height /= 2;
542            }
543            if (i >= minLevel && i <= maxLevel) {
544               if (!t->Image[0][i]) {
545                  t->_Complete = GL_FALSE;
546                  incomplete(t, "2D Image[0][i] == NULL");
547                  return;
548               }
549               if (t->Image[0][i]->Width2 != width) {
550                  t->_Complete = GL_FALSE;
551                  incomplete(t, "2D Image[0][i] bad width");
552                  return;
553               }
554               if (t->Image[0][i]->Height2 != height) {
555                  t->_Complete = GL_FALSE;
556                  incomplete(t, "2D Image[0][i] bad height");
557                  return;
558               }
559               if (width==1 && height==1) {
560                  return;  /* found smallest needed mipmap, all done! */
561               }
562            }
563         }
564      }
565      else if (t->Target == GL_TEXTURE_3D) {
566         /* Test 3-D mipmaps */
567         GLuint width = t->Image[0][baseLevel]->Width2;
568         GLuint height = t->Image[0][baseLevel]->Height2;
569         GLuint depth = t->Image[0][baseLevel]->Depth2;
570	 for (i = baseLevel + 1; i < maxLevels; i++) {
571            if (width > 1) {
572               width /= 2;
573            }
574            if (height > 1) {
575               height /= 2;
576            }
577            if (depth > 1) {
578               depth /= 2;
579            }
580            if (i >= minLevel && i <= maxLevel) {
581               if (!t->Image[0][i]) {
582                  incomplete(t, "3D Image[0][i] == NULL");
583                  t->_Complete = GL_FALSE;
584                  return;
585               }
586               if (t->Image[0][i]->_BaseFormat == GL_DEPTH_COMPONENT) {
587                  t->_Complete = GL_FALSE;
588                  incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex");
589                  return;
590               }
591               if (t->Image[0][i]->Width2 != width) {
592                  t->_Complete = GL_FALSE;
593                  incomplete(t, "3D Image[0][i] bad width");
594                  return;
595               }
596               if (t->Image[0][i]->Height2 != height) {
597                  t->_Complete = GL_FALSE;
598                  incomplete(t, "3D Image[0][i] bad height");
599                  return;
600               }
601               if (t->Image[0][i]->Depth2 != depth) {
602                  t->_Complete = GL_FALSE;
603                  incomplete(t, "3D Image[0][i] bad depth");
604                  return;
605               }
606            }
607            if (width == 1 && height == 1 && depth == 1) {
608               return;  /* found smallest needed mipmap, all done! */
609            }
610         }
611      }
612      else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
613         /* make sure 6 cube faces are consistant */
614         GLuint width = t->Image[0][baseLevel]->Width2;
615         GLuint height = t->Image[0][baseLevel]->Height2;
616	 for (i = baseLevel + 1; i < maxLevels; i++) {
617            if (width > 1) {
618               width /= 2;
619            }
620            if (height > 1) {
621               height /= 2;
622            }
623            if (i >= minLevel && i <= maxLevel) {
624	       GLuint face;
625	       for (face = 0; face < 6; face++) {
626		  /* check that we have images defined */
627		  if (!t->Image[face][i]) {
628		     t->_Complete = GL_FALSE;
629		     incomplete(t, "CubeMap Image[n][i] == NULL");
630		     return;
631		  }
632		  /* Don't support GL_DEPTH_COMPONENT for cube maps */
633		  if (t->Image[face][i]->_BaseFormat == GL_DEPTH_COMPONENT) {
634		     t->_Complete = GL_FALSE;
635		     incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex");
636		     return;
637		  }
638		  /* check that all six images have same size */
639		  if (t->Image[face][i]->Width2!=width ||
640		      t->Image[face][i]->Height2!=height) {
641		     t->_Complete = GL_FALSE;
642		     incomplete(t, "CubeMap Image[n][i] bad size");
643		     return;
644		  }
645	       }
646	    }
647	    if (width == 1 && height == 1) {
648	       return;  /* found smallest needed mipmap, all done! */
649            }
650         }
651      }
652      else if (t->Target == GL_TEXTURE_RECTANGLE_NV) {
653         /* XXX special checking? */
654      }
655      else {
656         /* Target = ??? */
657         _mesa_problem(ctx, "Bug in gl_test_texture_object_completeness\n");
658      }
659   }
660}
661
662/*@}*/
663
664
665/***********************************************************************/
666/** \name API functions */
667/*@{*/
668
669
670/**
671 * Generate texture names.
672 *
673 * \param n number of texture names to be generated.
674 * \param textures an array in which will hold the generated texture names.
675 *
676 * \sa glGenTextures().
677 *
678 * Calls _mesa_HashFindFreeKeyBlock() to find a block of free texture
679 * IDs which are stored in \p textures.  Corresponding empty texture
680 * objects are also generated.
681 */
682void GLAPIENTRY
683_mesa_GenTextures( GLsizei n, GLuint *textures )
684{
685   GET_CURRENT_CONTEXT(ctx);
686   GLuint first;
687   GLint i;
688   ASSERT_OUTSIDE_BEGIN_END(ctx);
689
690   if (n < 0) {
691      _mesa_error( ctx, GL_INVALID_VALUE, "glGenTextures" );
692      return;
693   }
694
695   if (!textures)
696      return;
697
698   /*
699    * This must be atomic (generation and allocation of texture IDs)
700    */
701   _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
702
703   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->TexObjects, n);
704
705   /* Allocate new, empty texture objects */
706   for (i = 0; i < n; i++) {
707      struct gl_texture_object *texObj;
708      GLuint name = first + i;
709      GLenum target = 0;
710      texObj = (*ctx->Driver.NewTextureObject)( ctx, name, target);
711      if (!texObj) {
712         _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
713         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures");
714         return;
715      }
716
717      /* insert into hash table */
718      _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj);
719
720      textures[i] = name;
721   }
722
723   _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
724}
725
726
727/**
728 * Check if the given texture object is bound to the current draw or
729 * read framebuffer.  If so, Unbind it.
730 */
731static void
732unbind_texobj_from_fbo(GLcontext *ctx, struct gl_texture_object *texObj)
733{
734   const GLuint n = (ctx->DrawBuffer == ctx->ReadBuffer) ? 1 : 2;
735   GLuint i;
736
737   for (i = 0; i < n; i++) {
738      struct gl_framebuffer *fb = (i == 0) ? ctx->DrawBuffer : ctx->ReadBuffer;
739      if (fb->Name) {
740         GLuint j;
741         for (j = 0; j < BUFFER_COUNT; j++) {
742            if (fb->Attachment[j].Type == GL_TEXTURE &&
743                fb->Attachment[j].Texture == texObj) {
744               _mesa_remove_attachment(ctx, fb->Attachment + j);
745            }
746         }
747      }
748   }
749}
750
751
752/**
753 * Check if the given texture object is bound to any texture image units and
754 * unbind it if so (revert to default textures).
755 */
756static void
757unbind_texobj_from_texunits(GLcontext *ctx, struct gl_texture_object *texObj)
758{
759   GLuint u, tex;
760
761   for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) {
762      struct gl_texture_unit *unit = &ctx->Texture.Unit[u];
763      for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) {
764         if (texObj == unit->CurrentTex[tex]) {
765            _mesa_reference_texobj(&unit->CurrentTex[tex],
766                                   ctx->Shared->DefaultTex[TEXTURE_1D_INDEX]);
767            ASSERT(unit->CurrentTex[tex]);
768            break;
769         }
770      }
771   }
772}
773
774
775/**
776 * Delete named textures.
777 *
778 * \param n number of textures to be deleted.
779 * \param textures array of texture IDs to be deleted.
780 *
781 * \sa glDeleteTextures().
782 *
783 * If we're about to delete a texture that's currently bound to any
784 * texture unit, unbind the texture first.  Decrement the reference
785 * count on the texture object and delete it if it's zero.
786 * Recall that texture objects can be shared among several rendering
787 * contexts.
788 */
789void GLAPIENTRY
790_mesa_DeleteTextures( GLsizei n, const GLuint *textures)
791{
792   GET_CURRENT_CONTEXT(ctx);
793   GLint i;
794   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */
795
796   if (!textures)
797      return;
798
799   for (i = 0; i < n; i++) {
800      if (textures[i] > 0) {
801         struct gl_texture_object *delObj
802            = _mesa_lookup_texture(ctx, textures[i]);
803
804         if (delObj) {
805	    _mesa_lock_texture(ctx, delObj);
806
807            /* Check if texture is bound to any framebuffer objects.
808             * If so, unbind.
809             * See section 4.4.2.3 of GL_EXT_framebuffer_object.
810             */
811            unbind_texobj_from_fbo(ctx, delObj);
812
813            /* Check if this texture is currently bound to any texture units.
814             * If so, unbind it.
815             */
816            unbind_texobj_from_texunits(ctx, delObj);
817
818	    _mesa_unlock_texture(ctx, delObj);
819
820            ctx->NewState |= _NEW_TEXTURE;
821
822            /* The texture _name_ is now free for re-use.
823             * Remove it from the hash table now.
824             */
825            _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
826            _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name);
827            _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
828
829            /* Unreference the texobj.  If refcount hits zero, the texture
830             * will be deleted.
831             */
832            _mesa_reference_texobj(&delObj, NULL);
833         }
834      }
835   }
836}
837
838
839/**
840 * Convert a GL texture target enum such as GL_TEXTURE_2D or GL_TEXTURE_3D
841 * into the corresponding Mesa texture target index.
842 * Return -1 if target is invalid.
843 */
844static GLint
845target_enum_to_index(GLenum target)
846{
847   switch (target) {
848   case GL_TEXTURE_1D:
849      return TEXTURE_1D_INDEX;
850   case GL_TEXTURE_2D:
851      return TEXTURE_2D_INDEX;
852   case GL_TEXTURE_3D:
853      return TEXTURE_3D_INDEX;
854   case GL_TEXTURE_CUBE_MAP_ARB:
855      return TEXTURE_CUBE_INDEX;
856   case GL_TEXTURE_RECTANGLE_NV:
857      return TEXTURE_RECT_INDEX;
858   case GL_TEXTURE_1D_ARRAY_EXT:
859      return TEXTURE_1D_ARRAY_INDEX;
860   case GL_TEXTURE_2D_ARRAY_EXT:
861      return TEXTURE_2D_ARRAY_INDEX;
862   default:
863      return -1;
864   }
865}
866
867
868/**
869 * Bind a named texture to a texturing target.
870 *
871 * \param target texture target.
872 * \param texName texture name.
873 *
874 * \sa glBindTexture().
875 *
876 * Determines the old texture object bound and returns immediately if rebinding
877 * the same texture.  Get the current texture which is either a default texture
878 * if name is null, a named texture from the hash, or a new texture if the
879 * given texture name is new. Increments its reference count, binds it, and
880 * calls dd_function_table::BindTexture. Decrements the old texture reference
881 * count and deletes it if it reaches zero.
882 */
883void GLAPIENTRY
884_mesa_BindTexture( GLenum target, GLuint texName )
885{
886   GET_CURRENT_CONTEXT(ctx);
887   const GLuint unit = ctx->Texture.CurrentUnit;
888   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
889   struct gl_texture_object *newTexObj = NULL, *defaultTexObj = NULL;
890   GLint targetIndex;
891   ASSERT_OUTSIDE_BEGIN_END(ctx);
892
893   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
894      _mesa_debug(ctx, "glBindTexture %s %d\n",
895                  _mesa_lookup_enum_by_nr(target), (GLint) texName);
896
897   targetIndex = target_enum_to_index(target);
898   if (targetIndex < 0) {
899      _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)");
900      return;
901   }
902   assert(targetIndex < NUM_TEXTURE_TARGETS);
903   defaultTexObj = ctx->Shared->DefaultTex[targetIndex];
904
905   /*
906    * Get pointer to new texture object (newTexObj)
907    */
908   if (texName == 0) {
909      newTexObj = defaultTexObj;
910   }
911   else {
912      /* non-default texture object */
913      newTexObj = _mesa_lookup_texture(ctx, texName);
914      if (newTexObj) {
915         /* error checking */
916         if (newTexObj->Target != 0 && newTexObj->Target != target) {
917            /* the named texture object's target doesn't match the given target */
918            _mesa_error( ctx, GL_INVALID_OPERATION,
919                         "glBindTexture(target mismatch)" );
920            return;
921         }
922         if (newTexObj->Target == 0) {
923            finish_texture_init(ctx, target, newTexObj);
924         }
925      }
926      else {
927         /* if this is a new texture id, allocate a texture object now */
928	 newTexObj = (*ctx->Driver.NewTextureObject)(ctx, texName, target);
929         if (!newTexObj) {
930            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture");
931            return;
932         }
933
934         /* and insert it into hash table */
935         _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
936         _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj);
937         _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
938      }
939      newTexObj->Target = target;
940   }
941
942   assert(valid_texture_object(newTexObj));
943
944   /* flush before changing binding */
945   FLUSH_VERTICES(ctx, _NEW_TEXTURE);
946
947   /* Do the actual binding.  The refcount on the previously bound
948    * texture object will be decremented.  It'll be deleted if the
949    * count hits zero.
950    */
951   _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], newTexObj);
952   ASSERT(texUnit->CurrentTex[targetIndex]);
953
954   /* Pass BindTexture call to device driver */
955   if (ctx->Driver.BindTexture)
956      (*ctx->Driver.BindTexture)( ctx, target, newTexObj );
957}
958
959
960/**
961 * Set texture priorities.
962 *
963 * \param n number of textures.
964 * \param texName texture names.
965 * \param priorities corresponding texture priorities.
966 *
967 * \sa glPrioritizeTextures().
968 *
969 * Looks up each texture in the hash, clamps the corresponding priority between
970 * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture.
971 */
972void GLAPIENTRY
973_mesa_PrioritizeTextures( GLsizei n, const GLuint *texName,
974                          const GLclampf *priorities )
975{
976   GET_CURRENT_CONTEXT(ctx);
977   GLint i;
978   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
979
980   if (n < 0) {
981      _mesa_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" );
982      return;
983   }
984
985   if (!priorities)
986      return;
987
988   for (i = 0; i < n; i++) {
989      if (texName[i] > 0) {
990         struct gl_texture_object *t = _mesa_lookup_texture(ctx, texName[i]);
991         if (t) {
992            t->Priority = CLAMP( priorities[i], 0.0F, 1.0F );
993	    if (ctx->Driver.PrioritizeTexture)
994	       ctx->Driver.PrioritizeTexture( ctx, t, t->Priority );
995         }
996      }
997   }
998
999   ctx->NewState |= _NEW_TEXTURE;
1000}
1001
1002/**
1003 * See if textures are loaded in texture memory.
1004 *
1005 * \param n number of textures to query.
1006 * \param texName array with the texture names.
1007 * \param residences array which will hold the residence status.
1008 *
1009 * \return GL_TRUE if all textures are resident and \p residences is left unchanged,
1010 *
1011 * \sa glAreTexturesResident().
1012 *
1013 * Looks up each texture in the hash and calls
1014 * dd_function_table::IsTextureResident.
1015 */
1016GLboolean GLAPIENTRY
1017_mesa_AreTexturesResident(GLsizei n, const GLuint *texName,
1018                          GLboolean *residences)
1019{
1020   GET_CURRENT_CONTEXT(ctx);
1021   GLboolean allResident = GL_TRUE;
1022   GLint i, j;
1023   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1024
1025   if (n < 0) {
1026      _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)");
1027      return GL_FALSE;
1028   }
1029
1030   if (!texName || !residences)
1031      return GL_FALSE;
1032
1033   for (i = 0; i < n; i++) {
1034      struct gl_texture_object *t;
1035      if (texName[i] == 0) {
1036         _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident");
1037         return GL_FALSE;
1038      }
1039      t = _mesa_lookup_texture(ctx, texName[i]);
1040      if (!t) {
1041         _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident");
1042         return GL_FALSE;
1043      }
1044      if (!ctx->Driver.IsTextureResident ||
1045          ctx->Driver.IsTextureResident(ctx, t)) {
1046         /* The texture is resident */
1047	 if (!allResident)
1048	    residences[i] = GL_TRUE;
1049      }
1050      else {
1051         /* The texture is not resident */
1052         if (allResident) {
1053	    allResident = GL_FALSE;
1054	    for (j = 0; j < i; j++)
1055	       residences[j] = GL_TRUE;
1056	 }
1057	 residences[i] = GL_FALSE;
1058      }
1059   }
1060
1061   return allResident;
1062}
1063
1064/**
1065 * See if a name corresponds to a texture.
1066 *
1067 * \param texture texture name.
1068 *
1069 * \return GL_TRUE if texture name corresponds to a texture, or GL_FALSE
1070 * otherwise.
1071 *
1072 * \sa glIsTexture().
1073 *
1074 * Calls _mesa_HashLookup().
1075 */
1076GLboolean GLAPIENTRY
1077_mesa_IsTexture( GLuint texture )
1078{
1079   struct gl_texture_object *t;
1080   GET_CURRENT_CONTEXT(ctx);
1081   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1082
1083   if (!texture)
1084      return GL_FALSE;
1085
1086   t = _mesa_lookup_texture(ctx, texture);
1087
1088   /* IsTexture is true only after object has been bound once. */
1089   return t && t->Target;
1090}
1091
1092
1093/**
1094 * Simplest implementation of texture locking: Grab the a new mutex in
1095 * the shared context.  Examine the shared context state timestamp and
1096 * if there has been a change, set the appropriate bits in
1097 * ctx->NewState.
1098 *
1099 * This is used to deal with synchronizing things when a texture object
1100 * is used/modified by different contexts (or threads) which are sharing
1101 * the texture.
1102 *
1103 * See also _mesa_lock/unlock_texture() in teximage.h
1104 */
1105void
1106_mesa_lock_context_textures( GLcontext *ctx )
1107{
1108   _glthread_LOCK_MUTEX(ctx->Shared->TexMutex);
1109
1110   if (ctx->Shared->TextureStateStamp != ctx->TextureStateTimestamp) {
1111      ctx->NewState |= _NEW_TEXTURE;
1112      ctx->TextureStateTimestamp = ctx->Shared->TextureStateStamp;
1113   }
1114}
1115
1116
1117void
1118_mesa_unlock_context_textures( GLcontext *ctx )
1119{
1120   assert(ctx->Shared->TextureStateStamp == ctx->TextureStateTimestamp);
1121   _glthread_UNLOCK_MUTEX(ctx->Shared->TexMutex);
1122}
1123
1124/*@}*/
1125
1126
1127