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