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