texgetimage.c revision 63396ce4c0fe067f69d1b53d0408627a421c4678
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.7 4 * 5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 6 * Copyright (c) 2009 VMware, Inc. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included 16 * in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 26 27/** 28 * Code for glGetTexImage() and glGetCompressedTexImage(). 29 */ 30 31 32#include "glheader.h" 33#include "bufferobj.h" 34#include "enums.h" 35#include "context.h" 36#include "formats.h" 37#include "format_unpack.h" 38#include "glformats.h" 39#include "image.h" 40#include "mfeatures.h" 41#include "mtypes.h" 42#include "pack.h" 43#include "pbo.h" 44#include "texcompress.h" 45#include "texgetimage.h" 46#include "teximage.h" 47 48 49 50/** 51 * Can the given type represent negative values? 52 */ 53static inline GLboolean 54type_needs_clamping(GLenum type) 55{ 56 switch (type) { 57 case GL_BYTE: 58 case GL_SHORT: 59 case GL_INT: 60 case GL_FLOAT: 61 case GL_HALF_FLOAT_ARB: 62 case GL_UNSIGNED_INT_10F_11F_11F_REV: 63 case GL_UNSIGNED_INT_5_9_9_9_REV: 64 return GL_FALSE; 65 default: 66 return GL_TRUE; 67 } 68} 69 70 71/** 72 * glGetTexImage for depth/Z pixels. 73 */ 74static void 75get_tex_depth(struct gl_context *ctx, GLuint dimensions, 76 GLenum format, GLenum type, GLvoid *pixels, 77 struct gl_texture_image *texImage) 78{ 79 const GLint width = texImage->Width; 80 const GLint height = texImage->Height; 81 const GLint depth = texImage->Depth; 82 GLint img, row; 83 GLfloat *depthRow = (GLfloat *) malloc(width * sizeof(GLfloat)); 84 85 if (!depthRow) { 86 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 87 return; 88 } 89 90 for (img = 0; img < depth; img++) { 91 GLubyte *srcMap; 92 GLint srcRowStride; 93 94 /* map src texture buffer */ 95 ctx->Driver.MapTextureImage(ctx, texImage, img, 96 0, 0, width, height, GL_MAP_READ_BIT, 97 &srcMap, &srcRowStride); 98 99 if (srcMap) { 100 for (row = 0; row < height; row++) { 101 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 102 width, height, format, type, 103 img, row, 0); 104 const GLubyte *src = srcMap + row * srcRowStride; 105 _mesa_unpack_float_z_row(texImage->TexFormat, width, src, depthRow); 106 _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack); 107 } 108 109 ctx->Driver.UnmapTextureImage(ctx, texImage, img); 110 } 111 else { 112 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 113 break; 114 } 115 } 116 117 free(depthRow); 118} 119 120 121/** 122 * glGetTexImage for depth/stencil pixels. 123 */ 124static void 125get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions, 126 GLenum format, GLenum type, GLvoid *pixels, 127 struct gl_texture_image *texImage) 128{ 129 const GLint width = texImage->Width; 130 const GLint height = texImage->Height; 131 const GLint depth = texImage->Depth; 132 GLint img, row; 133 134 for (img = 0; img < depth; img++) { 135 GLubyte *srcMap; 136 GLint rowstride; 137 138 /* map src texture buffer */ 139 ctx->Driver.MapTextureImage(ctx, texImage, img, 140 0, 0, width, height, GL_MAP_READ_BIT, 141 &srcMap, &rowstride); 142 143 if (srcMap) { 144 for (row = 0; row < height; row++) { 145 const GLubyte *src = srcMap + row * rowstride; 146 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 147 width, height, format, type, 148 img, row, 0); 149 /* XXX Z24_S8 vs. S8_Z24??? */ 150 memcpy(dest, src, width * sizeof(GLuint)); 151 if (ctx->Pack.SwapBytes) { 152 _mesa_swap4((GLuint *) dest, width); 153 } 154 } 155 156 ctx->Driver.UnmapTextureImage(ctx, texImage, img); 157 } 158 else { 159 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 160 break; 161 } 162 } 163} 164 165 166/** 167 * glGetTexImage for YCbCr pixels. 168 */ 169static void 170get_tex_ycbcr(struct gl_context *ctx, GLuint dimensions, 171 GLenum format, GLenum type, GLvoid *pixels, 172 struct gl_texture_image *texImage) 173{ 174 const GLint width = texImage->Width; 175 const GLint height = texImage->Height; 176 const GLint depth = texImage->Depth; 177 GLint img, row; 178 179 for (img = 0; img < depth; img++) { 180 GLubyte *srcMap; 181 GLint rowstride; 182 183 /* map src texture buffer */ 184 ctx->Driver.MapTextureImage(ctx, texImage, img, 185 0, 0, width, height, GL_MAP_READ_BIT, 186 &srcMap, &rowstride); 187 188 if (srcMap) { 189 for (row = 0; row < height; row++) { 190 const GLubyte *src = srcMap + row * rowstride; 191 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 192 width, height, format, type, 193 img, row, 0); 194 memcpy(dest, src, width * sizeof(GLushort)); 195 196 /* check for byte swapping */ 197 if ((texImage->TexFormat == MESA_FORMAT_YCBCR 198 && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) || 199 (texImage->TexFormat == MESA_FORMAT_YCBCR_REV 200 && type == GL_UNSIGNED_SHORT_8_8_MESA)) { 201 if (!ctx->Pack.SwapBytes) 202 _mesa_swap2((GLushort *) dest, width); 203 } 204 else if (ctx->Pack.SwapBytes) { 205 _mesa_swap2((GLushort *) dest, width); 206 } 207 } 208 209 ctx->Driver.UnmapTextureImage(ctx, texImage, img); 210 } 211 else { 212 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 213 break; 214 } 215 } 216} 217 218 219/** 220 * Get a color texture image with decompression. 221 */ 222static void 223get_tex_rgba_compressed(struct gl_context *ctx, GLuint dimensions, 224 GLenum format, GLenum type, GLvoid *pixels, 225 struct gl_texture_image *texImage, 226 GLbitfield transferOps) 227{ 228 /* don't want to apply sRGB -> RGB conversion here so override the format */ 229 const gl_format texFormat = 230 _mesa_get_srgb_format_linear(texImage->TexFormat); 231 const GLenum baseFormat = _mesa_get_format_base_format(texFormat); 232 const GLuint width = texImage->Width; 233 const GLuint height = texImage->Height; 234 const GLuint depth = texImage->Depth; 235 GLfloat *tempImage, *srcRow; 236 GLuint row; 237 238 /* Decompress into temp float buffer, then pack into user buffer */ 239 tempImage = (GLfloat *) malloc(width * height * depth 240 * 4 * sizeof(GLfloat)); 241 if (!tempImage) { 242 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); 243 return; 244 } 245 246 /* Decompress the texture image - results in 'tempImage' */ 247 { 248 GLubyte *srcMap; 249 GLint srcRowStride; 250 251 ctx->Driver.MapTextureImage(ctx, texImage, 0, 252 0, 0, width, height, 253 GL_MAP_READ_BIT, 254 &srcMap, &srcRowStride); 255 if (srcMap) { 256 _mesa_decompress_image(texFormat, width, height, 257 srcMap, srcRowStride, tempImage); 258 259 ctx->Driver.UnmapTextureImage(ctx, texImage, 0); 260 } 261 else { 262 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 263 free(tempImage); 264 return; 265 } 266 } 267 268 if (baseFormat == GL_LUMINANCE || 269 baseFormat == GL_LUMINANCE_ALPHA) { 270 _mesa_rebase_rgba_float(width * height, (GLfloat (*)[4]) tempImage, 271 baseFormat); 272 } 273 274 srcRow = tempImage; 275 for (row = 0; row < height; row++) { 276 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 277 width, height, format, type, 278 0, row, 0); 279 280 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) srcRow, 281 format, type, dest, &ctx->Pack, transferOps); 282 srcRow += width * 4; 283 } 284 285 free(tempImage); 286} 287 288 289/** 290 * Get an uncompressed color texture image. 291 */ 292static void 293get_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions, 294 GLenum format, GLenum type, GLvoid *pixels, 295 struct gl_texture_image *texImage, 296 GLbitfield transferOps) 297{ 298 /* don't want to apply sRGB -> RGB conversion here so override the format */ 299 const gl_format texFormat = 300 _mesa_get_srgb_format_linear(texImage->TexFormat); 301 const GLuint width = texImage->Width; 302 const GLenum destBaseFormat = _mesa_base_tex_format(ctx, format); 303 GLenum rebaseFormat = GL_NONE; 304 GLuint height = texImage->Height; 305 GLuint depth = texImage->Depth; 306 GLuint img, row; 307 GLfloat (*rgba)[4]; 308 GLuint (*rgba_uint)[4]; 309 GLboolean tex_is_integer = _mesa_is_format_integer_color(texImage->TexFormat); 310 GLboolean tex_is_uint = _mesa_is_format_unsigned(texImage->TexFormat); 311 312 /* Allocate buffer for one row of texels */ 313 rgba = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat)); 314 rgba_uint = (GLuint (*)[4]) rgba; 315 if (!rgba) { 316 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); 317 return; 318 } 319 320 if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) { 321 depth = height; 322 height = 1; 323 } 324 325 if (texImage->_BaseFormat == GL_LUMINANCE || 326 texImage->_BaseFormat == GL_INTENSITY || 327 texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { 328 /* If a luminance (or intensity) texture is read back as RGB(A), the 329 * returned value should be (L,0,0,1), not (L,L,L,1). Set rebaseFormat 330 * here to get G=B=0. 331 */ 332 rebaseFormat = texImage->_BaseFormat; 333 } 334 else if ((texImage->_BaseFormat == GL_RGBA || 335 texImage->_BaseFormat == GL_RGB) && 336 (destBaseFormat == GL_LUMINANCE || 337 destBaseFormat == GL_LUMINANCE_ALPHA || 338 destBaseFormat == GL_LUMINANCE_INTEGER_EXT || 339 destBaseFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT)) { 340 /* If we're reading back an RGB(A) texture as luminance then we need 341 * to return L=tex(R). Note, that's different from glReadPixels which 342 * returns L=R+G+B. 343 */ 344 rebaseFormat = GL_LUMINANCE_ALPHA; /* this covers GL_LUMINANCE too */ 345 } 346 347 for (img = 0; img < depth; img++) { 348 GLubyte *srcMap; 349 GLint rowstride; 350 351 /* map src texture buffer */ 352 ctx->Driver.MapTextureImage(ctx, texImage, img, 353 0, 0, width, height, GL_MAP_READ_BIT, 354 &srcMap, &rowstride); 355 if (srcMap) { 356 for (row = 0; row < height; row++) { 357 const GLubyte *src = srcMap + row * rowstride; 358 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 359 width, height, format, type, 360 img, row, 0); 361 362 if (tex_is_integer) { 363 _mesa_unpack_uint_rgba_row(texFormat, width, src, rgba_uint); 364 if (rebaseFormat) 365 _mesa_rebase_rgba_uint(width, rgba_uint, rebaseFormat); 366 if (tex_is_uint) { 367 _mesa_pack_rgba_span_from_uints(ctx, width, 368 (GLuint (*)[4]) rgba_uint, 369 format, type, dest); 370 } else { 371 _mesa_pack_rgba_span_from_ints(ctx, width, 372 (GLint (*)[4]) rgba_uint, 373 format, type, dest); 374 } 375 } else { 376 _mesa_unpack_rgba_row(texFormat, width, src, rgba); 377 if (rebaseFormat) 378 _mesa_rebase_rgba_float(width, rgba, rebaseFormat); 379 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, 380 format, type, dest, 381 &ctx->Pack, transferOps); 382 } 383 } 384 385 /* Unmap the src texture buffer */ 386 ctx->Driver.UnmapTextureImage(ctx, texImage, img); 387 } 388 else { 389 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 390 break; 391 } 392 } 393 394 free(rgba); 395} 396 397 398/** 399 * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc). 400 * Compressed textures are handled here as well. 401 */ 402static void 403get_tex_rgba(struct gl_context *ctx, GLuint dimensions, 404 GLenum format, GLenum type, GLvoid *pixels, 405 struct gl_texture_image *texImage) 406{ 407 const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat); 408 GLbitfield transferOps = 0x0; 409 410 /* In general, clamping does not apply to glGetTexImage, except when 411 * the returned type of the image can't hold negative values. 412 */ 413 if (type_needs_clamping(type)) { 414 /* the returned image type can't have negative values */ 415 if (dataType == GL_FLOAT || 416 dataType == GL_SIGNED_NORMALIZED || 417 format == GL_LUMINANCE || 418 format == GL_LUMINANCE_ALPHA) { 419 transferOps |= IMAGE_CLAMP_BIT; 420 } 421 } 422 /* This applies to RGB, RGBA textures. if the format is either LUMINANCE 423 * or LUMINANCE ALPHA, luminance (L) is computed as L=R+G+B .we need to 424 * clamp the sum to [0,1]. 425 */ 426 else if ((format == GL_LUMINANCE || 427 format == GL_LUMINANCE_ALPHA) && 428 dataType == GL_UNSIGNED_NORMALIZED) { 429 transferOps |= IMAGE_CLAMP_BIT; 430 } 431 432 if (_mesa_is_format_compressed(texImage->TexFormat)) { 433 get_tex_rgba_compressed(ctx, dimensions, format, type, 434 pixels, texImage, transferOps); 435 } 436 else { 437 get_tex_rgba_uncompressed(ctx, dimensions, format, type, 438 pixels, texImage, transferOps); 439 } 440} 441 442 443/** 444 * Try to do glGetTexImage() with simple memcpy(). 445 * \return GL_TRUE if done, GL_FALSE otherwise 446 */ 447static GLboolean 448get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type, 449 GLvoid *pixels, 450 struct gl_texture_image *texImage) 451{ 452 const GLenum target = texImage->TexObject->Target; 453 GLboolean memCopy = GL_FALSE; 454 455 /* 456 * Check if we can use memcpy to copy from the hardware texture 457 * format to the user's format/type. 458 * Note that GL's pixel transfer ops don't apply to glGetTexImage() 459 */ 460 if (target == GL_TEXTURE_1D || 461 target == GL_TEXTURE_2D || 462 target == GL_TEXTURE_RECTANGLE || 463 _mesa_is_cube_face(target)) { 464 memCopy = _mesa_format_matches_format_and_type(texImage->TexFormat, 465 format, type, 466 ctx->Pack.SwapBytes); 467 } 468 469 if (memCopy) { 470 const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat); 471 const GLuint bytesPerRow = texImage->Width * bpp; 472 GLubyte *dst = 473 _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width, 474 texImage->Height, format, type, 0, 0); 475 const GLint dstRowStride = 476 _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type); 477 GLubyte *src; 478 GLint srcRowStride; 479 480 /* map src texture buffer */ 481 ctx->Driver.MapTextureImage(ctx, texImage, 0, 482 0, 0, texImage->Width, texImage->Height, 483 GL_MAP_READ_BIT, &src, &srcRowStride); 484 485 if (src) { 486 if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) { 487 memcpy(dst, src, bytesPerRow * texImage->Height); 488 } 489 else { 490 GLuint row; 491 for (row = 0; row < texImage->Height; row++) { 492 memcpy(dst, src, bytesPerRow); 493 dst += dstRowStride; 494 src += srcRowStride; 495 } 496 } 497 498 /* unmap src texture buffer */ 499 ctx->Driver.UnmapTextureImage(ctx, texImage, 0); 500 } 501 else { 502 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 503 } 504 } 505 506 return memCopy; 507} 508 509 510/** 511 * This is the software fallback for Driver.GetTexImage(). 512 * All error checking will have been done before this routine is called. 513 * We'll call ctx->Driver.MapTextureImage() to access the data, then 514 * unmap with ctx->Driver.UnmapTextureImage(). 515 */ 516void 517_mesa_get_teximage(struct gl_context *ctx, 518 GLenum format, GLenum type, GLvoid *pixels, 519 struct gl_texture_image *texImage) 520{ 521 GLuint dimensions; 522 523 switch (texImage->TexObject->Target) { 524 case GL_TEXTURE_1D: 525 dimensions = 1; 526 break; 527 case GL_TEXTURE_3D: 528 dimensions = 3; 529 break; 530 default: 531 dimensions = 2; 532 } 533 534 /* map dest buffer, if PBO */ 535 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 536 /* Packing texture image into a PBO. 537 * Map the (potentially) VRAM-based buffer into our process space so 538 * we can write into it with the code below. 539 * A hardware driver might use a sophisticated blit to move the 540 * texture data to the PBO if the PBO is in VRAM along with the texture. 541 */ 542 GLubyte *buf = (GLubyte *) 543 ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size, 544 GL_MAP_WRITE_BIT, ctx->Pack.BufferObj); 545 if (!buf) { 546 /* out of memory or other unexpected error */ 547 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)"); 548 return; 549 } 550 /* <pixels> was an offset into the PBO. 551 * Now make it a real, client-side pointer inside the mapped region. 552 */ 553 pixels = ADD_POINTERS(buf, pixels); 554 } 555 556 if (get_tex_memcpy(ctx, format, type, pixels, texImage)) { 557 /* all done */ 558 } 559 else if (format == GL_DEPTH_COMPONENT) { 560 get_tex_depth(ctx, dimensions, format, type, pixels, texImage); 561 } 562 else if (format == GL_DEPTH_STENCIL_EXT) { 563 get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage); 564 } 565 else if (format == GL_YCBCR_MESA) { 566 get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage); 567 } 568 else { 569 get_tex_rgba(ctx, dimensions, format, type, pixels, texImage); 570 } 571 572 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 573 ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj); 574 } 575} 576 577 578 579/** 580 * This is the software fallback for Driver.GetCompressedTexImage(). 581 * All error checking will have been done before this routine is called. 582 */ 583void 584_mesa_get_compressed_teximage(struct gl_context *ctx, 585 struct gl_texture_image *texImage, 586 GLvoid *img) 587{ 588 const GLuint row_stride = 589 _mesa_format_row_stride(texImage->TexFormat, texImage->Width); 590 GLuint i; 591 GLubyte *src; 592 GLint srcRowStride; 593 594 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 595 /* pack texture image into a PBO */ 596 GLubyte *buf = (GLubyte *) 597 ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size, 598 GL_MAP_WRITE_BIT, ctx->Pack.BufferObj); 599 if (!buf) { 600 /* out of memory or other unexpected error */ 601 _mesa_error(ctx, GL_OUT_OF_MEMORY, 602 "glGetCompresssedTexImage(map PBO failed)"); 603 return; 604 } 605 img = ADD_POINTERS(buf, img); 606 } 607 608 /* map src texture buffer */ 609 ctx->Driver.MapTextureImage(ctx, texImage, 0, 610 0, 0, texImage->Width, texImage->Height, 611 GL_MAP_READ_BIT, &src, &srcRowStride); 612 613 if (src) { 614 /* no pixelstore or pixel transfer, but respect stride */ 615 616 if (row_stride == srcRowStride) { 617 const GLuint size = _mesa_format_image_size(texImage->TexFormat, 618 texImage->Width, 619 texImage->Height, 620 texImage->Depth); 621 memcpy(img, src, size); 622 } 623 else { 624 GLuint bw, bh; 625 _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh); 626 for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) { 627 memcpy((GLubyte *)img + i * row_stride, 628 (GLubyte *)src + i * srcRowStride, 629 row_stride); 630 } 631 } 632 633 ctx->Driver.UnmapTextureImage(ctx, texImage, 0); 634 } 635 else { 636 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage"); 637 } 638 639 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 640 ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj); 641 } 642} 643 644 645/** 646 * Validate the texture target enum supplied to glTexImage or 647 * glCompressedTexImage. 648 */ 649static GLboolean 650legal_getteximage_target(struct gl_context *ctx, GLenum target) 651{ 652 switch (target) { 653 case GL_TEXTURE_1D: 654 case GL_TEXTURE_2D: 655 case GL_TEXTURE_3D: 656 return GL_TRUE; 657 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: 658 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: 659 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: 660 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: 661 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: 662 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: 663 return ctx->Extensions.ARB_texture_cube_map; 664 case GL_TEXTURE_RECTANGLE_NV: 665 return ctx->Extensions.NV_texture_rectangle; 666 case GL_TEXTURE_1D_ARRAY_EXT: 667 case GL_TEXTURE_2D_ARRAY_EXT: 668 return (ctx->Extensions.MESA_texture_array || 669 ctx->Extensions.EXT_texture_array); 670 default: 671 return GL_FALSE; 672 } 673} 674 675 676/** 677 * Do error checking for a glGetTexImage() call. 678 * \return GL_TRUE if any error, GL_FALSE if no errors. 679 */ 680static GLboolean 681getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level, 682 GLenum format, GLenum type, GLsizei clientMemSize, 683 GLvoid *pixels ) 684{ 685 struct gl_texture_object *texObj; 686 struct gl_texture_image *texImage; 687 const GLint maxLevels = _mesa_max_texture_levels(ctx, target); 688 const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; 689 GLenum baseFormat, err; 690 691 if (!legal_getteximage_target(ctx, target)) { 692 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target); 693 return GL_TRUE; 694 } 695 696 assert(maxLevels != 0); 697 if (level < 0 || level >= maxLevels) { 698 _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" ); 699 return GL_TRUE; 700 } 701 702 err = _mesa_error_check_format_and_type(ctx, format, type); 703 if (err != GL_NO_ERROR) { 704 _mesa_error(ctx, err, "glGetTexImage(format/type)"); 705 return GL_TRUE; 706 } 707 708 texObj = _mesa_get_current_tex_object(ctx, target); 709 710 if (!texObj) { 711 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)"); 712 return GL_TRUE; 713 } 714 715 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 716 if (!texImage) { 717 /* non-existant texture image */ 718 return GL_TRUE; 719 } 720 721 baseFormat = _mesa_get_format_base_format(texImage->TexFormat); 722 723 /* Make sure the requested image format is compatible with the 724 * texture's format. 725 */ 726 if (_mesa_is_color_format(format) 727 && !_mesa_is_color_format(baseFormat)) { 728 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 729 return GL_TRUE; 730 } 731 else if (_mesa_is_depth_format(format) 732 && !_mesa_is_depth_format(baseFormat) 733 && !_mesa_is_depthstencil_format(baseFormat)) { 734 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 735 return GL_TRUE; 736 } 737 else if (_mesa_is_ycbcr_format(format) 738 && !_mesa_is_ycbcr_format(baseFormat)) { 739 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 740 return GL_TRUE; 741 } 742 else if (_mesa_is_depthstencil_format(format) 743 && !_mesa_is_depthstencil_format(baseFormat)) { 744 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 745 return GL_TRUE; 746 } 747 else if (_mesa_is_dudv_format(format) 748 && !_mesa_is_dudv_format(baseFormat)) { 749 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 750 return GL_TRUE; 751 } 752 753 if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width, 754 texImage->Height, texImage->Depth, 755 format, type, clientMemSize, pixels)) { 756 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 757 _mesa_error(ctx, GL_INVALID_OPERATION, 758 "glGetTexImage(out of bounds PBO access)"); 759 } else { 760 _mesa_error(ctx, GL_INVALID_OPERATION, 761 "glGetnTexImageARB(out of bounds access:" 762 " bufSize (%d) is too small)", clientMemSize); 763 } 764 return GL_TRUE; 765 } 766 767 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 768 /* PBO should not be mapped */ 769 if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { 770 _mesa_error(ctx, GL_INVALID_OPERATION, 771 "glGetTexImage(PBO is mapped)"); 772 return GL_TRUE; 773 } 774 } 775 776 return GL_FALSE; 777} 778 779 780 781/** 782 * Get texture image. Called by glGetTexImage. 783 * 784 * \param target texture target. 785 * \param level image level. 786 * \param format pixel data format for returned image. 787 * \param type pixel data type for returned image. 788 * \param bufSize size of the pixels data buffer. 789 * \param pixels returned pixel data. 790 */ 791void GLAPIENTRY 792_mesa_GetnTexImageARB( GLenum target, GLint level, GLenum format, 793 GLenum type, GLsizei bufSize, GLvoid *pixels ) 794{ 795 struct gl_texture_object *texObj; 796 struct gl_texture_image *texImage; 797 GET_CURRENT_CONTEXT(ctx); 798 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 799 800 if (getteximage_error_check(ctx, target, level, format, type, 801 bufSize, pixels)) { 802 return; 803 } 804 805 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) { 806 /* not an error, do nothing */ 807 return; 808 } 809 810 texObj = _mesa_get_current_tex_object(ctx, target); 811 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 812 813 if (_mesa_is_zero_size_texture(texImage)) 814 return; 815 816 if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { 817 _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d," 818 " dstFmt=0x%x, dstType=0x%x\n", 819 texObj->Name, 820 _mesa_get_format_name(texImage->TexFormat), 821 texImage->Width, texImage->Height, 822 format, type); 823 } 824 825 _mesa_lock_texture(ctx, texObj); 826 { 827 ctx->Driver.GetTexImage(ctx, format, type, pixels, texImage); 828 } 829 _mesa_unlock_texture(ctx, texObj); 830} 831 832 833void GLAPIENTRY 834_mesa_GetTexImage( GLenum target, GLint level, GLenum format, 835 GLenum type, GLvoid *pixels ) 836{ 837 _mesa_GetnTexImageARB(target, level, format, type, INT_MAX, pixels); 838} 839 840 841/** 842 * Do error checking for a glGetCompressedTexImage() call. 843 * \return GL_TRUE if any error, GL_FALSE if no errors. 844 */ 845static GLboolean 846getcompressedteximage_error_check(struct gl_context *ctx, GLenum target, 847 GLint level, GLsizei clientMemSize, GLvoid *img) 848{ 849 struct gl_texture_object *texObj; 850 struct gl_texture_image *texImage; 851 const GLint maxLevels = _mesa_max_texture_levels(ctx, target); 852 GLuint compressedSize; 853 854 if (!legal_getteximage_target(ctx, target)) { 855 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)", 856 target); 857 return GL_TRUE; 858 } 859 860 assert(maxLevels != 0); 861 if (level < 0 || level >= maxLevels) { 862 _mesa_error(ctx, GL_INVALID_VALUE, 863 "glGetCompressedTexImageARB(bad level = %d)", level); 864 return GL_TRUE; 865 } 866 867 texObj = _mesa_get_current_tex_object(ctx, target); 868 if (!texObj) { 869 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)"); 870 return GL_TRUE; 871 } 872 873 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 874 875 if (!texImage) { 876 /* probably invalid mipmap level */ 877 _mesa_error(ctx, GL_INVALID_VALUE, 878 "glGetCompressedTexImageARB(level)"); 879 return GL_TRUE; 880 } 881 882 if (!_mesa_is_format_compressed(texImage->TexFormat)) { 883 _mesa_error(ctx, GL_INVALID_OPERATION, 884 "glGetCompressedTexImageARB(texture is not compressed)"); 885 return GL_TRUE; 886 } 887 888 compressedSize = _mesa_format_image_size(texImage->TexFormat, 889 texImage->Width, 890 texImage->Height, 891 texImage->Depth); 892 893 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 894 /* do bounds checking on writing to client memory */ 895 if (clientMemSize < compressedSize) { 896 _mesa_error(ctx, GL_INVALID_OPERATION, 897 "glGetnCompressedTexImageARB(out of bounds access:" 898 " bufSize (%d) is too small)", clientMemSize); 899 return GL_TRUE; 900 } 901 } else { 902 /* do bounds checking on PBO write */ 903 if ((const GLubyte *) img + compressedSize > 904 (const GLubyte *) ctx->Pack.BufferObj->Size) { 905 _mesa_error(ctx, GL_INVALID_OPERATION, 906 "glGetCompressedTexImage(out of bounds PBO access)"); 907 return GL_TRUE; 908 } 909 910 /* make sure PBO is not mapped */ 911 if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { 912 _mesa_error(ctx, GL_INVALID_OPERATION, 913 "glGetCompressedTexImage(PBO is mapped)"); 914 return GL_TRUE; 915 } 916 } 917 918 return GL_FALSE; 919} 920 921 922void GLAPIENTRY 923_mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize, 924 GLvoid *img) 925{ 926 struct gl_texture_object *texObj; 927 struct gl_texture_image *texImage; 928 GET_CURRENT_CONTEXT(ctx); 929 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 930 931 if (getcompressedteximage_error_check(ctx, target, level, bufSize, img)) { 932 return; 933 } 934 935 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) { 936 /* not an error, do nothing */ 937 return; 938 } 939 940 texObj = _mesa_get_current_tex_object(ctx, target); 941 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 942 943 if (_mesa_is_zero_size_texture(texImage)) 944 return; 945 946 if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { 947 _mesa_debug(ctx, 948 "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n", 949 texObj->Name, 950 _mesa_get_format_name(texImage->TexFormat), 951 texImage->Width, texImage->Height); 952 } 953 954 _mesa_lock_texture(ctx, texObj); 955 { 956 ctx->Driver.GetCompressedTexImage(ctx, texImage, img); 957 } 958 _mesa_unlock_texture(ctx, texObj); 959} 960 961void GLAPIENTRY 962_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img) 963{ 964 _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img); 965} 966