i965: don't emit state when dri_bufmgr_check_aperture_space fails.
[mesa.git] / src / mesa / main / texobj.c
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 */
55 struct 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 */
79 struct 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 */
96 void
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 */
148 static void
149 finish_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 */
180 void
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 */
222 void
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 */
262 static GLboolean
263 valid_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 */
290 void
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
355 static void
356 incomplete(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 */
377 void
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 /* Always need the base level image */
387 if (!t->Image[0][baseLevel]) {
388 char s[100];
389 _mesa_sprintf(s, "obj %p (%d) Image[baseLevel=%d] == NULL",
390 (void *) t, t->Name, baseLevel);
391 incomplete(t, s);
392 t->_Complete = GL_FALSE;
393 return;
394 }
395
396 /* Check width/height/depth for zero */
397 if (t->Image[0][baseLevel]->Width == 0 ||
398 t->Image[0][baseLevel]->Height == 0 ||
399 t->Image[0][baseLevel]->Depth == 0) {
400 incomplete(t, "texture width = 0");
401 t->_Complete = GL_FALSE;
402 return;
403 }
404
405 /* Compute _MaxLevel */
406 if ((t->Target == GL_TEXTURE_1D) ||
407 (t->Target == GL_TEXTURE_1D_ARRAY_EXT)) {
408 maxLog2 = t->Image[0][baseLevel]->WidthLog2;
409 maxLevels = ctx->Const.MaxTextureLevels;
410 }
411 else if ((t->Target == GL_TEXTURE_2D) ||
412 (t->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
413 maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2,
414 t->Image[0][baseLevel]->HeightLog2);
415 maxLevels = ctx->Const.MaxTextureLevels;
416 }
417 else if (t->Target == GL_TEXTURE_3D) {
418 GLint max = MAX2(t->Image[0][baseLevel]->WidthLog2,
419 t->Image[0][baseLevel]->HeightLog2);
420 maxLog2 = MAX2(max, (GLint)(t->Image[0][baseLevel]->DepthLog2));
421 maxLevels = ctx->Const.Max3DTextureLevels;
422 }
423 else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
424 maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2,
425 t->Image[0][baseLevel]->HeightLog2);
426 maxLevels = ctx->Const.MaxCubeTextureLevels;
427 }
428 else if (t->Target == GL_TEXTURE_RECTANGLE_NV) {
429 maxLog2 = 0; /* not applicable */
430 maxLevels = 1; /* no mipmapping */
431 }
432 else {
433 _mesa_problem(ctx, "Bad t->Target in _mesa_test_texobj_completeness");
434 return;
435 }
436
437 ASSERT(maxLevels > 0);
438
439 t->_MaxLevel = baseLevel + maxLog2;
440 t->_MaxLevel = MIN2(t->_MaxLevel, t->MaxLevel);
441 t->_MaxLevel = MIN2(t->_MaxLevel, maxLevels - 1);
442
443 /* Compute _MaxLambda = q - b (see the 1.2 spec) used during mipmapping */
444 t->_MaxLambda = (GLfloat) (t->_MaxLevel - t->BaseLevel);
445
446 if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
447 /* make sure that all six cube map level 0 images are the same size */
448 const GLuint w = t->Image[0][baseLevel]->Width2;
449 const GLuint h = t->Image[0][baseLevel]->Height2;
450 GLuint face;
451 for (face = 1; face < 6; face++) {
452 if (t->Image[face][baseLevel] == NULL ||
453 t->Image[face][baseLevel]->Width2 != w ||
454 t->Image[face][baseLevel]->Height2 != h) {
455 t->_Complete = GL_FALSE;
456 incomplete(t, "Non-quare cubemap image");
457 return;
458 }
459 }
460 }
461
462 /* extra checking for mipmaps */
463 if (t->MinFilter != GL_NEAREST && t->MinFilter != GL_LINEAR) {
464 /*
465 * Mipmapping: determine if we have a complete set of mipmaps
466 */
467 GLint i;
468 GLint minLevel = baseLevel;
469 GLint maxLevel = t->_MaxLevel;
470
471 if (minLevel > maxLevel) {
472 t->_Complete = GL_FALSE;
473 incomplete(t, "minLevel > maxLevel");
474 return;
475 }
476
477 /* Test dimension-independent attributes */
478 for (i = minLevel; i <= maxLevel; i++) {
479 if (t->Image[0][i]) {
480 if (t->Image[0][i]->TexFormat != t->Image[0][baseLevel]->TexFormat) {
481 t->_Complete = GL_FALSE;
482 incomplete(t, "Format[i] != Format[baseLevel]");
483 return;
484 }
485 if (t->Image[0][i]->Border != t->Image[0][baseLevel]->Border) {
486 t->_Complete = GL_FALSE;
487 incomplete(t, "Border[i] != Border[baseLevel]");
488 return;
489 }
490 }
491 }
492
493 /* Test things which depend on number of texture image dimensions */
494 if ((t->Target == GL_TEXTURE_1D) ||
495 (t->Target == GL_TEXTURE_1D_ARRAY_EXT)) {
496 /* Test 1-D mipmaps */
497 GLuint width = t->Image[0][baseLevel]->Width2;
498 for (i = baseLevel + 1; i < maxLevels; i++) {
499 if (width > 1) {
500 width /= 2;
501 }
502 if (i >= minLevel && i <= maxLevel) {
503 if (!t->Image[0][i]) {
504 t->_Complete = GL_FALSE;
505 incomplete(t, "1D Image[0][i] == NULL");
506 return;
507 }
508 if (t->Image[0][i]->Width2 != width ) {
509 t->_Complete = GL_FALSE;
510 incomplete(t, "1D Image[0][i] bad width");
511 return;
512 }
513 }
514 if (width == 1) {
515 return; /* found smallest needed mipmap, all done! */
516 }
517 }
518 }
519 else if ((t->Target == GL_TEXTURE_2D) ||
520 (t->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
521 /* Test 2-D mipmaps */
522 GLuint width = t->Image[0][baseLevel]->Width2;
523 GLuint height = t->Image[0][baseLevel]->Height2;
524 for (i = baseLevel + 1; i < maxLevels; i++) {
525 if (width > 1) {
526 width /= 2;
527 }
528 if (height > 1) {
529 height /= 2;
530 }
531 if (i >= minLevel && i <= maxLevel) {
532 if (!t->Image[0][i]) {
533 t->_Complete = GL_FALSE;
534 incomplete(t, "2D Image[0][i] == NULL");
535 return;
536 }
537 if (t->Image[0][i]->Width2 != width) {
538 t->_Complete = GL_FALSE;
539 incomplete(t, "2D Image[0][i] bad width");
540 return;
541 }
542 if (t->Image[0][i]->Height2 != height) {
543 t->_Complete = GL_FALSE;
544 incomplete(t, "2D Image[0][i] bad height");
545 return;
546 }
547 if (width==1 && height==1) {
548 return; /* found smallest needed mipmap, all done! */
549 }
550 }
551 }
552 }
553 else if (t->Target == GL_TEXTURE_3D) {
554 /* Test 3-D mipmaps */
555 GLuint width = t->Image[0][baseLevel]->Width2;
556 GLuint height = t->Image[0][baseLevel]->Height2;
557 GLuint depth = t->Image[0][baseLevel]->Depth2;
558 for (i = baseLevel + 1; i < maxLevels; i++) {
559 if (width > 1) {
560 width /= 2;
561 }
562 if (height > 1) {
563 height /= 2;
564 }
565 if (depth > 1) {
566 depth /= 2;
567 }
568 if (i >= minLevel && i <= maxLevel) {
569 if (!t->Image[0][i]) {
570 incomplete(t, "3D Image[0][i] == NULL");
571 t->_Complete = GL_FALSE;
572 return;
573 }
574 if (t->Image[0][i]->_BaseFormat == GL_DEPTH_COMPONENT) {
575 t->_Complete = GL_FALSE;
576 incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex");
577 return;
578 }
579 if (t->Image[0][i]->Width2 != width) {
580 t->_Complete = GL_FALSE;
581 incomplete(t, "3D Image[0][i] bad width");
582 return;
583 }
584 if (t->Image[0][i]->Height2 != height) {
585 t->_Complete = GL_FALSE;
586 incomplete(t, "3D Image[0][i] bad height");
587 return;
588 }
589 if (t->Image[0][i]->Depth2 != depth) {
590 t->_Complete = GL_FALSE;
591 incomplete(t, "3D Image[0][i] bad depth");
592 return;
593 }
594 }
595 if (width == 1 && height == 1 && depth == 1) {
596 return; /* found smallest needed mipmap, all done! */
597 }
598 }
599 }
600 else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) {
601 /* make sure 6 cube faces are consistant */
602 GLuint width = t->Image[0][baseLevel]->Width2;
603 GLuint height = t->Image[0][baseLevel]->Height2;
604 for (i = baseLevel + 1; i < maxLevels; i++) {
605 if (width > 1) {
606 width /= 2;
607 }
608 if (height > 1) {
609 height /= 2;
610 }
611 if (i >= minLevel && i <= maxLevel) {
612 GLuint face;
613 for (face = 0; face < 6; face++) {
614 /* check that we have images defined */
615 if (!t->Image[face][i]) {
616 t->_Complete = GL_FALSE;
617 incomplete(t, "CubeMap Image[n][i] == NULL");
618 return;
619 }
620 /* Don't support GL_DEPTH_COMPONENT for cube maps */
621 if (t->Image[face][i]->_BaseFormat == GL_DEPTH_COMPONENT) {
622 t->_Complete = GL_FALSE;
623 incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex");
624 return;
625 }
626 /* check that all six images have same size */
627 if (t->Image[face][i]->Width2!=width ||
628 t->Image[face][i]->Height2!=height) {
629 t->_Complete = GL_FALSE;
630 incomplete(t, "CubeMap Image[n][i] bad size");
631 return;
632 }
633 }
634 }
635 if (width == 1 && height == 1) {
636 return; /* found smallest needed mipmap, all done! */
637 }
638 }
639 }
640 else if (t->Target == GL_TEXTURE_RECTANGLE_NV) {
641 /* XXX special checking? */
642 }
643 else {
644 /* Target = ??? */
645 _mesa_problem(ctx, "Bug in gl_test_texture_object_completeness\n");
646 }
647 }
648 }
649
650 /*@}*/
651
652
653 /***********************************************************************/
654 /** \name API functions */
655 /*@{*/
656
657
658 /**
659 * Generate texture names.
660 *
661 * \param n number of texture names to be generated.
662 * \param textures an array in which will hold the generated texture names.
663 *
664 * \sa glGenTextures().
665 *
666 * Calls _mesa_HashFindFreeKeyBlock() to find a block of free texture
667 * IDs which are stored in \p textures. Corresponding empty texture
668 * objects are also generated.
669 */
670 void GLAPIENTRY
671 _mesa_GenTextures( GLsizei n, GLuint *textures )
672 {
673 GET_CURRENT_CONTEXT(ctx);
674 GLuint first;
675 GLint i;
676 ASSERT_OUTSIDE_BEGIN_END(ctx);
677
678 if (n < 0) {
679 _mesa_error( ctx, GL_INVALID_VALUE, "glGenTextures" );
680 return;
681 }
682
683 if (!textures)
684 return;
685
686 /*
687 * This must be atomic (generation and allocation of texture IDs)
688 */
689 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
690
691 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->TexObjects, n);
692
693 /* Allocate new, empty texture objects */
694 for (i = 0; i < n; i++) {
695 struct gl_texture_object *texObj;
696 GLuint name = first + i;
697 GLenum target = 0;
698 texObj = (*ctx->Driver.NewTextureObject)( ctx, name, target);
699 if (!texObj) {
700 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
701 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures");
702 return;
703 }
704
705 /* insert into hash table */
706 _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj);
707
708 textures[i] = name;
709 }
710
711 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
712 }
713
714
715 /**
716 * Check if the given texture object is bound to the current draw or
717 * read framebuffer. If so, Unbind it.
718 */
719 static void
720 unbind_texobj_from_fbo(GLcontext *ctx, struct gl_texture_object *texObj)
721 {
722 const GLuint n = (ctx->DrawBuffer == ctx->ReadBuffer) ? 1 : 2;
723 GLuint i;
724
725 for (i = 0; i < n; i++) {
726 struct gl_framebuffer *fb = (i == 0) ? ctx->DrawBuffer : ctx->ReadBuffer;
727 if (fb->Name) {
728 GLuint j;
729 for (j = 0; j < BUFFER_COUNT; j++) {
730 if (fb->Attachment[j].Type == GL_TEXTURE &&
731 fb->Attachment[j].Texture == texObj) {
732 _mesa_remove_attachment(ctx, fb->Attachment + j);
733 }
734 }
735 }
736 }
737 }
738
739
740 /**
741 * Check if the given texture object is bound to any texture image units and
742 * unbind it if so (revert to default textures).
743 */
744 static void
745 unbind_texobj_from_texunits(GLcontext *ctx, struct gl_texture_object *texObj)
746 {
747 GLuint u;
748
749 for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) {
750 struct gl_texture_unit *unit = &ctx->Texture.Unit[u];
751 if (texObj == unit->Current1D) {
752 _mesa_reference_texobj(&unit->Current1D, ctx->Shared->Default1D);
753 }
754 else if (texObj == unit->Current2D) {
755 _mesa_reference_texobj(&unit->Current2D, ctx->Shared->Default2D);
756 }
757 else if (texObj == unit->Current3D) {
758 _mesa_reference_texobj(&unit->Current3D, ctx->Shared->Default3D);
759 }
760 else if (texObj == unit->CurrentCubeMap) {
761 _mesa_reference_texobj(&unit->CurrentCubeMap, ctx->Shared->DefaultCubeMap);
762 }
763 else if (texObj == unit->CurrentRect) {
764 _mesa_reference_texobj(&unit->CurrentRect, ctx->Shared->DefaultRect);
765 }
766 else if (texObj == unit->Current1DArray) {
767 _mesa_reference_texobj(&unit->Current1DArray, ctx->Shared->Default1DArray);
768 }
769 else if (texObj == unit->Current2DArray) {
770 _mesa_reference_texobj(&unit->Current2DArray, ctx->Shared->Default2DArray);
771 }
772 }
773 }
774
775
776 /**
777 * Delete named textures.
778 *
779 * \param n number of textures to be deleted.
780 * \param textures array of texture IDs to be deleted.
781 *
782 * \sa glDeleteTextures().
783 *
784 * If we're about to delete a texture that's currently bound to any
785 * texture unit, unbind the texture first. Decrement the reference
786 * count on the texture object and delete it if it's zero.
787 * Recall that texture objects can be shared among several rendering
788 * contexts.
789 */
790 void GLAPIENTRY
791 _mesa_DeleteTextures( GLsizei n, const GLuint *textures)
792 {
793 GET_CURRENT_CONTEXT(ctx);
794 GLint i;
795 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */
796
797 if (!textures)
798 return;
799
800 for (i = 0; i < n; i++) {
801 if (textures[i] > 0) {
802 struct gl_texture_object *delObj
803 = _mesa_lookup_texture(ctx, textures[i]);
804
805 if (delObj) {
806 _mesa_lock_texture(ctx, delObj);
807
808 /* Check if texture is bound to any framebuffer objects.
809 * If so, unbind.
810 * See section 4.4.2.3 of GL_EXT_framebuffer_object.
811 */
812 unbind_texobj_from_fbo(ctx, delObj);
813
814 /* Check if this texture is currently bound to any texture units.
815 * If so, unbind it.
816 */
817 unbind_texobj_from_texunits(ctx, delObj);
818
819 _mesa_unlock_texture(ctx, delObj);
820
821 ctx->NewState |= _NEW_TEXTURE;
822
823 /* The texture _name_ is now free for re-use.
824 * Remove it from the hash table now.
825 */
826 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
827 _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name);
828 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
829
830 /* Unreference the texobj. If refcount hits zero, the texture
831 * will be deleted.
832 */
833 _mesa_reference_texobj(&delObj, NULL);
834 }
835 }
836 }
837 }
838
839
840 /**
841 * Bind a named texture to a texturing target.
842 *
843 * \param target texture target.
844 * \param texName texture name.
845 *
846 * \sa glBindTexture().
847 *
848 * Determines the old texture object bound and returns immediately if rebinding
849 * the same texture. Get the current texture which is either a default texture
850 * if name is null, a named texture from the hash, or a new texture if the
851 * given texture name is new. Increments its reference count, binds it, and
852 * calls dd_function_table::BindTexture. Decrements the old texture reference
853 * count and deletes it if it reaches zero.
854 */
855 void GLAPIENTRY
856 _mesa_BindTexture( GLenum target, GLuint texName )
857 {
858 GET_CURRENT_CONTEXT(ctx);
859 const GLuint unit = ctx->Texture.CurrentUnit;
860 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
861 struct gl_texture_object *newTexObj = NULL, *defaultTexObj = NULL;
862 ASSERT_OUTSIDE_BEGIN_END(ctx);
863
864 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
865 _mesa_debug(ctx, "glBindTexture %s %d\n",
866 _mesa_lookup_enum_by_nr(target), (GLint) texName);
867
868 switch (target) {
869 case GL_TEXTURE_1D:
870 defaultTexObj = ctx->Shared->Default1D;
871 break;
872 case GL_TEXTURE_2D:
873 defaultTexObj = ctx->Shared->Default2D;
874 break;
875 case GL_TEXTURE_3D:
876 defaultTexObj = ctx->Shared->Default3D;
877 break;
878 case GL_TEXTURE_CUBE_MAP_ARB:
879 defaultTexObj = ctx->Shared->DefaultCubeMap;
880 break;
881 case GL_TEXTURE_RECTANGLE_NV:
882 defaultTexObj = ctx->Shared->DefaultRect;
883 break;
884 case GL_TEXTURE_1D_ARRAY_EXT:
885 defaultTexObj = ctx->Shared->Default1DArray;
886 break;
887 case GL_TEXTURE_2D_ARRAY_EXT:
888 defaultTexObj = ctx->Shared->Default2DArray;
889 break;
890 default:
891 _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)");
892 return;
893 }
894
895 /*
896 * Get pointer to new texture object (newTexObj)
897 */
898 if (texName == 0) {
899 newTexObj = defaultTexObj;
900 }
901 else {
902 /* non-default texture object */
903 newTexObj = _mesa_lookup_texture(ctx, texName);
904 if (newTexObj) {
905 /* error checking */
906 if (newTexObj->Target != 0 && newTexObj->Target != target) {
907 /* the named texture object's target doesn't match the given target */
908 _mesa_error( ctx, GL_INVALID_OPERATION,
909 "glBindTexture(target mismatch)" );
910 return;
911 }
912 if (newTexObj->Target == 0) {
913 finish_texture_init(ctx, target, newTexObj);
914 }
915 }
916 else {
917 /* if this is a new texture id, allocate a texture object now */
918 newTexObj = (*ctx->Driver.NewTextureObject)(ctx, texName, target);
919 if (!newTexObj) {
920 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture");
921 return;
922 }
923
924 /* and insert it into hash table */
925 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
926 _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj);
927 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
928 }
929 newTexObj->Target = target;
930 }
931
932 assert(valid_texture_object(newTexObj));
933
934 /* flush before changing binding */
935 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
936
937 /* Do the actual binding. The refcount on the previously bound
938 * texture object will be decremented. It'll be deleted if the
939 * count hits zero.
940 */
941 switch (target) {
942 case GL_TEXTURE_1D:
943 _mesa_reference_texobj(&texUnit->Current1D, newTexObj);
944 break;
945 case GL_TEXTURE_2D:
946 _mesa_reference_texobj(&texUnit->Current2D, newTexObj);
947 break;
948 case GL_TEXTURE_3D:
949 _mesa_reference_texobj(&texUnit->Current3D, newTexObj);
950 break;
951 case GL_TEXTURE_CUBE_MAP_ARB:
952 _mesa_reference_texobj(&texUnit->CurrentCubeMap, newTexObj);
953 break;
954 case GL_TEXTURE_RECTANGLE_NV:
955 _mesa_reference_texobj(&texUnit->CurrentRect, newTexObj);
956 break;
957 case GL_TEXTURE_1D_ARRAY_EXT:
958 texUnit->Current1DArray = newTexObj;
959 break;
960 case GL_TEXTURE_2D_ARRAY_EXT:
961 texUnit->Current2DArray = newTexObj;
962 break;
963 default:
964 /* Bad target should be caught above */
965 _mesa_problem(ctx, "bad target in BindTexture");
966 return;
967 }
968
969 /* Pass BindTexture call to device driver */
970 if (ctx->Driver.BindTexture)
971 (*ctx->Driver.BindTexture)( ctx, target, newTexObj );
972 }
973
974
975 /**
976 * Set texture priorities.
977 *
978 * \param n number of textures.
979 * \param texName texture names.
980 * \param priorities corresponding texture priorities.
981 *
982 * \sa glPrioritizeTextures().
983 *
984 * Looks up each texture in the hash, clamps the corresponding priority between
985 * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture.
986 */
987 void GLAPIENTRY
988 _mesa_PrioritizeTextures( GLsizei n, const GLuint *texName,
989 const GLclampf *priorities )
990 {
991 GET_CURRENT_CONTEXT(ctx);
992 GLint i;
993 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
994
995 if (n < 0) {
996 _mesa_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" );
997 return;
998 }
999
1000 if (!priorities)
1001 return;
1002
1003 for (i = 0; i < n; i++) {
1004 if (texName[i] > 0) {
1005 struct gl_texture_object *t = _mesa_lookup_texture(ctx, texName[i]);
1006 if (t) {
1007 t->Priority = CLAMP( priorities[i], 0.0F, 1.0F );
1008 if (ctx->Driver.PrioritizeTexture)
1009 ctx->Driver.PrioritizeTexture( ctx, t, t->Priority );
1010 }
1011 }
1012 }
1013
1014 ctx->NewState |= _NEW_TEXTURE;
1015 }
1016
1017 /**
1018 * See if textures are loaded in texture memory.
1019 *
1020 * \param n number of textures to query.
1021 * \param texName array with the texture names.
1022 * \param residences array which will hold the residence status.
1023 *
1024 * \return GL_TRUE if all textures are resident and \p residences is left unchanged,
1025 *
1026 * \sa glAreTexturesResident().
1027 *
1028 * Looks up each texture in the hash and calls
1029 * dd_function_table::IsTextureResident.
1030 */
1031 GLboolean GLAPIENTRY
1032 _mesa_AreTexturesResident(GLsizei n, const GLuint *texName,
1033 GLboolean *residences)
1034 {
1035 GET_CURRENT_CONTEXT(ctx);
1036 GLboolean allResident = GL_TRUE;
1037 GLint i, j;
1038 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1039
1040 if (n < 0) {
1041 _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)");
1042 return GL_FALSE;
1043 }
1044
1045 if (!texName || !residences)
1046 return GL_FALSE;
1047
1048 for (i = 0; i < n; i++) {
1049 struct gl_texture_object *t;
1050 if (texName[i] == 0) {
1051 _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident");
1052 return GL_FALSE;
1053 }
1054 t = _mesa_lookup_texture(ctx, texName[i]);
1055 if (!t) {
1056 _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident");
1057 return GL_FALSE;
1058 }
1059 if (!ctx->Driver.IsTextureResident ||
1060 ctx->Driver.IsTextureResident(ctx, t)) {
1061 /* The texture is resident */
1062 if (!allResident)
1063 residences[i] = GL_TRUE;
1064 }
1065 else {
1066 /* The texture is not resident */
1067 if (allResident) {
1068 allResident = GL_FALSE;
1069 for (j = 0; j < i; j++)
1070 residences[j] = GL_TRUE;
1071 }
1072 residences[i] = GL_FALSE;
1073 }
1074 }
1075
1076 return allResident;
1077 }
1078
1079 /**
1080 * See if a name corresponds to a texture.
1081 *
1082 * \param texture texture name.
1083 *
1084 * \return GL_TRUE if texture name corresponds to a texture, or GL_FALSE
1085 * otherwise.
1086 *
1087 * \sa glIsTexture().
1088 *
1089 * Calls _mesa_HashLookup().
1090 */
1091 GLboolean GLAPIENTRY
1092 _mesa_IsTexture( GLuint texture )
1093 {
1094 struct gl_texture_object *t;
1095 GET_CURRENT_CONTEXT(ctx);
1096 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1097
1098 if (!texture)
1099 return GL_FALSE;
1100
1101 t = _mesa_lookup_texture(ctx, texture);
1102
1103 /* IsTexture is true only after object has been bound once. */
1104 return t && t->Target;
1105 }
1106
1107
1108 /**
1109 * Simplest implementation of texture locking: Grab the a new mutex in
1110 * the shared context. Examine the shared context state timestamp and
1111 * if there has been a change, set the appropriate bits in
1112 * ctx->NewState.
1113 *
1114 * This is used to deal with synchronizing things when a texture object
1115 * is used/modified by different contexts (or threads) which are sharing
1116 * the texture.
1117 *
1118 * See also _mesa_lock/unlock_texture() in teximage.h
1119 */
1120 void
1121 _mesa_lock_context_textures( GLcontext *ctx )
1122 {
1123 _glthread_LOCK_MUTEX(ctx->Shared->TexMutex);
1124
1125 if (ctx->Shared->TextureStateStamp != ctx->TextureStateTimestamp) {
1126 ctx->NewState |= _NEW_TEXTURE;
1127 ctx->TextureStateTimestamp = ctx->Shared->TextureStateStamp;
1128 }
1129 }
1130
1131
1132 void
1133 _mesa_unlock_context_textures( GLcontext *ctx )
1134 {
1135 assert(ctx->Shared->TextureStateStamp == ctx->TextureStateTimestamp);
1136 _glthread_UNLOCK_MUTEX(ctx->Shared->TexMutex);
1137 }
1138
1139 /*@}*/
1140
1141