1 /* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 2011 VMware, Inc. All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 /** 26 * \file texstorage.c 27 * GL_ARB_texture_storage functions 28 */ 29 30 #include "glheader.h" 31 #include "context.h" 32 #include "enums.h" 33 #include "imports.h" 34 #include "macros.h" 35 #include "teximage.h" 36 #include "texobj.h" 37 #include "mipmap.h" 38 #include "texstorage.h" 39 #include "textureview.h" 40 #include "mtypes.h" 41 #include "glformats.h" 42 #include "hash.h" 43 44 45 /** 46 * Check if the given texture target is a legal texture object target 47 * for a glTexStorage() command. 48 * This is a bit different than legal_teximage_target() when it comes 49 * to cube maps. 50 */ 51 static bool 52 legal_texobj_target(const struct gl_context *ctx, GLuint dims, GLenum target) 53 { 54 if (dims < 1 || dims > 3) { 55 _mesa_problem(ctx, "invalid dims=%u in legal_texobj_target()", dims); 56 return false; 57 } 58 59 switch (dims) { 60 case 2: 61 switch (target) { 62 case GL_TEXTURE_2D: 63 return true; 64 case GL_TEXTURE_CUBE_MAP: 65 return ctx->Extensions.ARB_texture_cube_map; 66 } 67 break; 68 case 3: 69 switch (target) { 70 case GL_TEXTURE_3D: 71 return true; 72 case GL_TEXTURE_2D_ARRAY: 73 return ctx->Extensions.EXT_texture_array; 74 case GL_TEXTURE_CUBE_MAP_ARRAY: 75 return _mesa_has_texture_cube_map_array(ctx); 76 } 77 break; 78 } 79 80 if (!_mesa_is_desktop_gl(ctx)) 81 return false; 82 83 switch (dims) { 84 case 1: 85 switch (target) { 86 case GL_TEXTURE_1D: 87 case GL_PROXY_TEXTURE_1D: 88 return true; 89 default: 90 return false; 91 } 92 case 2: 93 switch (target) { 94 case GL_PROXY_TEXTURE_2D: 95 return true; 96 case GL_PROXY_TEXTURE_CUBE_MAP: 97 return ctx->Extensions.ARB_texture_cube_map; 98 case GL_TEXTURE_RECTANGLE: 99 case GL_PROXY_TEXTURE_RECTANGLE: 100 return ctx->Extensions.NV_texture_rectangle; 101 case GL_TEXTURE_1D_ARRAY: 102 case GL_PROXY_TEXTURE_1D_ARRAY: 103 return ctx->Extensions.EXT_texture_array; 104 default: 105 return false; 106 } 107 case 3: 108 switch (target) { 109 case GL_PROXY_TEXTURE_3D: 110 return true; 111 case GL_PROXY_TEXTURE_2D_ARRAY: 112 return ctx->Extensions.EXT_texture_array; 113 case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY: 114 return ctx->Extensions.ARB_texture_cube_map_array; 115 default: 116 return false; 117 } 118 default: 119 unreachable("impossible dimensions"); 120 } 121 } 122 123 124 /** Helper to get a particular texture image in a texture object */ 125 static struct gl_texture_image * 126 get_tex_image(struct gl_context *ctx, 127 struct gl_texture_object *texObj, 128 GLuint face, GLuint level) 129 { 130 const GLenum faceTarget = 131 (texObj->Target == GL_TEXTURE_CUBE_MAP || 132 texObj->Target == GL_PROXY_TEXTURE_CUBE_MAP) 133 ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + face : texObj->Target; 134 return _mesa_get_tex_image(ctx, texObj, faceTarget, level); 135 } 136 137 138 139 static GLboolean 140 initialize_texture_fields(struct gl_context *ctx, 141 struct gl_texture_object *texObj, 142 GLint levels, 143 GLsizei width, GLsizei height, GLsizei depth, 144 GLenum internalFormat, mesa_format texFormat) 145 { 146 const GLenum target = texObj->Target; 147 const GLuint numFaces = _mesa_num_tex_faces(target); 148 GLint level, levelWidth = width, levelHeight = height, levelDepth = depth; 149 GLuint face; 150 151 /* Set up all the texture object's gl_texture_images */ 152 for (level = 0; level < levels; level++) { 153 for (face = 0; face < numFaces; face++) { 154 struct gl_texture_image *texImage = 155 get_tex_image(ctx, texObj, face, level); 156 157 if (!texImage) { 158 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage"); 159 return GL_FALSE; 160 } 161 162 _mesa_init_teximage_fields(ctx, texImage, 163 levelWidth, levelHeight, levelDepth, 164 0, internalFormat, texFormat); 165 } 166 167 _mesa_next_mipmap_level_size(target, 0, 168 levelWidth, levelHeight, levelDepth, 169 &levelWidth, &levelHeight, &levelDepth); 170 } 171 return GL_TRUE; 172 } 173 174 175 /** 176 * Clear all fields of texture object to zeros. Used for proxy texture tests 177 * and to clean up when a texture memory allocation fails. 178 */ 179 static void 180 clear_texture_fields(struct gl_context *ctx, 181 struct gl_texture_object *texObj) 182 { 183 const GLenum target = texObj->Target; 184 const GLuint numFaces = _mesa_num_tex_faces(target); 185 GLint level; 186 GLuint face; 187 188 for (level = 0; level < ARRAY_SIZE(texObj->Image[0]); level++) { 189 for (face = 0; face < numFaces; face++) { 190 struct gl_texture_image *texImage = 191 get_tex_image(ctx, texObj, face, level); 192 193 if (!texImage) { 194 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage"); 195 return; 196 } 197 198 _mesa_clear_texture_image(ctx, texImage); 199 } 200 } 201 } 202 203 204 /** 205 * Update/re-validate framebuffer object. 206 */ 207 static void 208 update_fbo_texture(struct gl_context *ctx, struct gl_texture_object *texObj) 209 { 210 const unsigned numFaces = _mesa_num_tex_faces(texObj->Target); 211 for (int level = 0; level < ARRAY_SIZE(texObj->Image[0]); level++) { 212 for (unsigned face = 0; face < numFaces; face++) 213 _mesa_update_fbo_texture(ctx, texObj, face, level); 214 } 215 } 216 217 218 GLboolean 219 _mesa_is_legal_tex_storage_format(const struct gl_context *ctx, 220 GLenum internalformat) 221 { 222 /* check internal format - note that only sized formats are allowed */ 223 switch (internalformat) { 224 case GL_ALPHA: 225 case GL_LUMINANCE: 226 case GL_LUMINANCE_ALPHA: 227 case GL_INTENSITY: 228 case GL_RED: 229 case GL_RG: 230 case GL_RGB: 231 case GL_RGBA: 232 case GL_BGRA: 233 case GL_DEPTH_COMPONENT: 234 case GL_DEPTH_STENCIL: 235 case GL_COMPRESSED_ALPHA: 236 case GL_COMPRESSED_LUMINANCE_ALPHA: 237 case GL_COMPRESSED_LUMINANCE: 238 case GL_COMPRESSED_INTENSITY: 239 case GL_COMPRESSED_RGB: 240 case GL_COMPRESSED_RGBA: 241 case GL_COMPRESSED_SRGB: 242 case GL_COMPRESSED_SRGB_ALPHA: 243 case GL_COMPRESSED_SLUMINANCE: 244 case GL_COMPRESSED_SLUMINANCE_ALPHA: 245 case GL_RED_INTEGER: 246 case GL_GREEN_INTEGER: 247 case GL_BLUE_INTEGER: 248 case GL_ALPHA_INTEGER: 249 case GL_RGB_INTEGER: 250 case GL_RGBA_INTEGER: 251 case GL_BGR_INTEGER: 252 case GL_BGRA_INTEGER: 253 case GL_LUMINANCE_INTEGER_EXT: 254 case GL_LUMINANCE_ALPHA_INTEGER_EXT: 255 /* these unsized formats are illegal */ 256 return GL_FALSE; 257 default: 258 return _mesa_base_tex_format(ctx, internalformat) > 0; 259 } 260 } 261 262 263 /** 264 * Default ctx->Driver.AllocTextureStorage() handler. 265 * 266 * The driver can override this with a more specific implementation if it 267 * desires, but this can be used to get the texture images allocated using the 268 * usual texture image handling code. The immutability of 269 * GL_ARB_texture_storage texture layouts is handled by texObj->Immutable 270 * checks at glTexImage* time. 271 */ 272 GLboolean 273 _mesa_AllocTextureStorage_sw(struct gl_context *ctx, 274 struct gl_texture_object *texObj, 275 GLsizei levels, GLsizei width, 276 GLsizei height, GLsizei depth) 277 { 278 const int numFaces = _mesa_num_tex_faces(texObj->Target); 279 int face; 280 int level; 281 282 (void) width; 283 (void) height; 284 (void) depth; 285 286 for (face = 0; face < numFaces; face++) { 287 for (level = 0; level < levels; level++) { 288 struct gl_texture_image *const texImage = texObj->Image[face][level]; 289 if (!ctx->Driver.AllocTextureImageBuffer(ctx, texImage)) 290 return GL_FALSE; 291 } 292 } 293 294 return GL_TRUE; 295 } 296 297 298 /** 299 * Do error checking for calls to glTexStorage1/2/3D(). 300 * If an error is found, record it with _mesa_error(), unless the target 301 * is a proxy texture. 302 * \return GL_TRUE if any error, GL_FALSE otherwise. 303 */ 304 static GLboolean 305 tex_storage_error_check(struct gl_context *ctx, 306 struct gl_texture_object *texObj, 307 GLuint dims, GLenum target, 308 GLsizei levels, GLenum internalformat, 309 GLsizei width, GLsizei height, GLsizei depth, 310 bool dsa) 311 { 312 const char* suffix = dsa ? "ture" : ""; 313 314 /* Legal format checking has been moved to texstorage and texturestorage in 315 * order to allow meta functions to use legacy formats. */ 316 317 /* size check */ 318 if (!_mesa_valid_tex_storage_dim(width, height, depth)) { 319 _mesa_error(ctx, GL_INVALID_VALUE, 320 "glTex%sStorage%uD(width, height or depth < 1)", 321 suffix, dims); 322 return GL_TRUE; 323 } 324 325 if (_mesa_is_compressed_format(ctx, internalformat)) { 326 GLenum err; 327 if (!_mesa_target_can_be_compressed(ctx, target, internalformat, &err)) { 328 _mesa_error(ctx, err, 329 "glTex%sStorage%dD(internalformat = %s)", suffix, dims, 330 _mesa_enum_to_string(internalformat)); 331 return GL_TRUE; 332 } 333 } 334 335 /* levels check */ 336 if (levels < 1) { 337 _mesa_error(ctx, GL_INVALID_VALUE, "glTex%sStorage%uD(levels < 1)", 338 suffix, dims); 339 return GL_TRUE; 340 } 341 342 /* check levels against maximum (note different error than above) */ 343 if (levels > (GLint) _mesa_max_texture_levels(ctx, target)) { 344 _mesa_error(ctx, GL_INVALID_OPERATION, 345 "glTex%sStorage%uD(levels too large)", 346 suffix, dims); 347 return GL_TRUE; 348 } 349 350 /* check levels against width/height/depth */ 351 if (levels > _mesa_get_tex_max_num_levels(target, width, height, depth)) { 352 _mesa_error(ctx, GL_INVALID_OPERATION, 353 "glTex%sStorage%uD(too many levels" 354 " for max texture dimension)", 355 suffix, dims); 356 return GL_TRUE; 357 } 358 359 /* non-default texture object check */ 360 if (!_mesa_is_proxy_texture(target) && (!texObj || (texObj->Name == 0))) { 361 _mesa_error(ctx, GL_INVALID_OPERATION, 362 "glTex%sStorage%uD(texture object 0)", 363 suffix, dims); 364 return GL_TRUE; 365 } 366 367 /* Check if texObj->Immutable is set */ 368 if (!_mesa_is_proxy_texture(target) && texObj->Immutable) { 369 _mesa_error(ctx, GL_INVALID_OPERATION, "glTex%sStorage%uD(immutable)", 370 suffix, dims); 371 return GL_TRUE; 372 } 373 374 /* additional checks for depth textures */ 375 if (!_mesa_legal_texture_base_format_for_target(ctx, target, internalformat)) { 376 _mesa_error(ctx, GL_INVALID_OPERATION, "glTex%sStorage%uD(bad target for texture)", 377 suffix, dims); 378 return GL_TRUE; 379 } 380 381 return GL_FALSE; 382 } 383 384 385 /** 386 * Helper that does the storage allocation for _mesa_TexStorage1/2/3D() 387 * and _mesa_TextureStorage1/2/3D(). 388 */ 389 void 390 _mesa_texture_storage(struct gl_context *ctx, GLuint dims, 391 struct gl_texture_object *texObj, 392 GLenum target, GLsizei levels, 393 GLenum internalformat, GLsizei width, 394 GLsizei height, GLsizei depth, bool dsa) 395 { 396 GLboolean sizeOK, dimensionsOK; 397 mesa_format texFormat; 398 const char* suffix = dsa ? "ture" : ""; 399 400 assert(texObj); 401 402 if (tex_storage_error_check(ctx, texObj, dims, target, levels, 403 internalformat, width, height, depth, dsa)) { 404 return; /* error was recorded */ 405 } 406 407 texFormat = _mesa_choose_texture_format(ctx, texObj, target, 0, 408 internalformat, GL_NONE, GL_NONE); 409 assert(texFormat != MESA_FORMAT_NONE); 410 411 /* check that width, height, depth are legal for the mipmap level */ 412 dimensionsOK = _mesa_legal_texture_dimensions(ctx, target, 0, 413 width, height, depth, 0); 414 415 sizeOK = ctx->Driver.TestProxyTexImage(ctx, target, levels, 0, texFormat, 416 1, width, height, depth); 417 418 if (_mesa_is_proxy_texture(target)) { 419 if (dimensionsOK && sizeOK) { 420 initialize_texture_fields(ctx, texObj, levels, width, height, depth, 421 internalformat, texFormat); 422 } 423 else { 424 /* clear all image fields for [levels] */ 425 clear_texture_fields(ctx, texObj); 426 } 427 } 428 else { 429 if (!dimensionsOK) { 430 _mesa_error(ctx, GL_INVALID_VALUE, 431 "glTex%sStorage%uD(invalid width, height or depth)", 432 suffix, dims); 433 return; 434 } 435 436 if (!sizeOK) { 437 _mesa_error(ctx, GL_OUT_OF_MEMORY, 438 "glTex%sStorage%uD(texture too large)", 439 suffix, dims); 440 } 441 442 assert(levels > 0); 443 assert(width > 0); 444 assert(height > 0); 445 assert(depth > 0); 446 447 if (!initialize_texture_fields(ctx, texObj, levels, width, height, depth, 448 internalformat, texFormat)) { 449 return; 450 } 451 452 /* Do actual texture memory allocation */ 453 if (!ctx->Driver.AllocTextureStorage(ctx, texObj, levels, 454 width, height, depth)) { 455 /* Reset the texture images' info to zeros. 456 * Strictly speaking, we probably don't have to do this since 457 * generating GL_OUT_OF_MEMORY can leave things in an undefined 458 * state but this puts things in a consistent state. 459 */ 460 clear_texture_fields(ctx, texObj); 461 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTex%sStorage%uD", 462 suffix, dims); 463 return; 464 } 465 466 _mesa_set_texture_view_state(ctx, texObj, target, levels); 467 468 update_fbo_texture(ctx, texObj); 469 } 470 } 471 472 473 /** 474 * Helper used by _mesa_TexStorage1/2/3D(). 475 */ 476 static void 477 texstorage(GLuint dims, GLenum target, GLsizei levels, GLenum internalformat, 478 GLsizei width, GLsizei height, GLsizei depth) 479 { 480 struct gl_texture_object *texObj; 481 GET_CURRENT_CONTEXT(ctx); 482 483 /* Check target. This is done here so that _mesa_texture_storage 484 * can receive unsized formats. 485 */ 486 if (!legal_texobj_target(ctx, dims, target)) { 487 _mesa_error(ctx, GL_INVALID_ENUM, 488 "glTexStorage%uD(illegal target=%s)", 489 dims, _mesa_enum_to_string(target)); 490 return; 491 } 492 493 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 494 _mesa_debug(ctx, "glTexStorage%uD %s %d %s %d %d %d\n", 495 dims, 496 _mesa_enum_to_string(target), levels, 497 _mesa_enum_to_string(internalformat), 498 width, height, depth); 499 500 /* Check the format to make sure it is sized. */ 501 if (!_mesa_is_legal_tex_storage_format(ctx, internalformat)) { 502 _mesa_error(ctx, GL_INVALID_ENUM, 503 "glTexStorage%uD(internalformat = %s)", dims, 504 _mesa_enum_to_string(internalformat)); 505 return; 506 } 507 508 texObj = _mesa_get_current_tex_object(ctx, target); 509 if (!texObj) 510 return; 511 512 _mesa_texture_storage(ctx, dims, texObj, target, levels, 513 internalformat, width, height, depth, false); 514 } 515 516 517 /** 518 * Helper used by _mesa_TextureStorage1/2/3D(). 519 */ 520 static void 521 texturestorage(GLuint dims, GLuint texture, GLsizei levels, 522 GLenum internalformat, GLsizei width, GLsizei height, 523 GLsizei depth) 524 { 525 struct gl_texture_object *texObj; 526 GET_CURRENT_CONTEXT(ctx); 527 528 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 529 _mesa_debug(ctx, "glTextureStorage%uD %d %d %s %d %d %d\n", 530 dims, texture, levels, 531 _mesa_enum_to_string(internalformat), 532 width, height, depth); 533 534 /* Check the format to make sure it is sized. */ 535 if (!_mesa_is_legal_tex_storage_format(ctx, internalformat)) { 536 _mesa_error(ctx, GL_INVALID_ENUM, 537 "glTextureStorage%uD(internalformat = %s)", dims, 538 _mesa_enum_to_string(internalformat)); 539 return; 540 } 541 542 /* Get the texture object by Name. */ 543 texObj = _mesa_lookup_texture(ctx, texture); 544 if (!texObj) { 545 _mesa_error(ctx, GL_INVALID_OPERATION, 546 "glTextureStorage%uD(texture = %d)", dims, texture); 547 return; 548 } 549 550 /* Check target. This is done here so that _mesa_texture_storage 551 * can receive unsized formats. 552 */ 553 if (!legal_texobj_target(ctx, dims, texObj->Target)) { 554 _mesa_error(ctx, GL_INVALID_ENUM, 555 "glTextureStorage%uD(illegal target=%s)", 556 dims, _mesa_enum_to_string(texObj->Target)); 557 return; 558 } 559 560 _mesa_texture_storage(ctx, dims, texObj, texObj->Target, 561 levels, internalformat, width, height, depth, true); 562 } 563 564 565 void GLAPIENTRY 566 _mesa_TexStorage1D(GLenum target, GLsizei levels, GLenum internalformat, 567 GLsizei width) 568 { 569 texstorage(1, target, levels, internalformat, width, 1, 1); 570 } 571 572 573 void GLAPIENTRY 574 _mesa_TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, 575 GLsizei width, GLsizei height) 576 { 577 texstorage(2, target, levels, internalformat, width, height, 1); 578 } 579 580 581 void GLAPIENTRY 582 _mesa_TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, 583 GLsizei width, GLsizei height, GLsizei depth) 584 { 585 texstorage(3, target, levels, internalformat, width, height, depth); 586 } 587 588 589 void GLAPIENTRY 590 _mesa_TextureStorage1D(GLuint texture, GLsizei levels, GLenum internalformat, 591 GLsizei width) 592 { 593 texturestorage(1, texture, levels, internalformat, width, 1, 1); 594 } 595 596 597 void GLAPIENTRY 598 _mesa_TextureStorage2D(GLuint texture, GLsizei levels, 599 GLenum internalformat, 600 GLsizei width, GLsizei height) 601 { 602 texturestorage(2, texture, levels, internalformat, width, height, 1); 603 } 604 605 606 void GLAPIENTRY 607 _mesa_TextureStorage3D(GLuint texture, GLsizei levels, GLenum internalformat, 608 GLsizei width, GLsizei height, GLsizei depth) 609 { 610 texturestorage(3, texture, levels, internalformat, width, height, depth); 611 } 612 613 614 /* 615 * Note: we don't support GL_EXT_direct_state_access and the spec says 616 * we don't need the following functions. However, glew checks for the 617 * presence of all six functions and will say that GL_ARB_texture_storage 618 * is not supported if these functions are missing. 619 */ 620 621 622 void GLAPIENTRY 623 _mesa_TextureStorage1DEXT(GLuint texture, GLenum target, GLsizei levels, 624 GLenum internalformat, 625 GLsizei width) 626 { 627 GET_CURRENT_CONTEXT(ctx); 628 629 (void) texture; 630 (void) target; 631 (void) levels; 632 (void) internalformat; 633 (void) width; 634 635 _mesa_error(ctx, GL_INVALID_OPERATION, 636 "glTextureStorage1DEXT not supported"); 637 } 638 639 640 void GLAPIENTRY 641 _mesa_TextureStorage2DEXT(GLuint texture, GLenum target, GLsizei levels, 642 GLenum internalformat, 643 GLsizei width, GLsizei height) 644 { 645 GET_CURRENT_CONTEXT(ctx); 646 647 (void) texture; 648 (void) target; 649 (void) levels; 650 (void) internalformat; 651 (void) width; 652 (void) height; 653 654 _mesa_error(ctx, GL_INVALID_OPERATION, 655 "glTextureStorage2DEXT not supported"); 656 } 657 658 659 void GLAPIENTRY 660 _mesa_TextureStorage3DEXT(GLuint texture, GLenum target, GLsizei levels, 661 GLenum internalformat, 662 GLsizei width, GLsizei height, GLsizei depth) 663 { 664 GET_CURRENT_CONTEXT(ctx); 665 666 (void) texture; 667 (void) target; 668 (void) levels; 669 (void) internalformat; 670 (void) width; 671 (void) height; 672 (void) depth; 673 674 _mesa_error(ctx, GL_INVALID_OPERATION, 675 "glTextureStorage3DEXT not supported"); 676 } 677