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 */ 53 static inline GLboolean 54 type_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 */ 74 static void 75 get_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 */ 124 static void 125 get_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 */ 169 static void 170 get_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 */ 222 static void 223 get_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 GLenum destBaseFormat = _mesa_base_tex_format(ctx, format); 233 GLenum rebaseFormat = GL_NONE; 234 const GLuint width = texImage->Width; 235 const GLuint height = texImage->Height; 236 const GLuint depth = texImage->Depth; 237 GLfloat *tempImage, *srcRow; 238 GLuint row; 239 240 /* Decompress into temp float buffer, then pack into user buffer */ 241 tempImage = (GLfloat *) malloc(width * height * depth 242 * 4 * sizeof(GLfloat)); 243 if (!tempImage) { 244 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); 245 return; 246 } 247 248 /* Decompress the texture image - results in 'tempImage' */ 249 { 250 GLubyte *srcMap; 251 GLint srcRowStride; 252 253 ctx->Driver.MapTextureImage(ctx, texImage, 0, 254 0, 0, width, height, 255 GL_MAP_READ_BIT, 256 &srcMap, &srcRowStride); 257 if (srcMap) { 258 _mesa_decompress_image(texFormat, width, height, 259 srcMap, srcRowStride, tempImage); 260 261 ctx->Driver.UnmapTextureImage(ctx, texImage, 0); 262 } 263 else { 264 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 265 free(tempImage); 266 return; 267 } 268 } 269 270 if (baseFormat == GL_LUMINANCE || 271 baseFormat == GL_INTENSITY || 272 baseFormat == GL_LUMINANCE_ALPHA) { 273 /* If a luminance (or intensity) texture is read back as RGB(A), the 274 * returned value should be (L,0,0,1), not (L,L,L,1). Set rebaseFormat 275 * here to get G=B=0. 276 */ 277 rebaseFormat = texImage->_BaseFormat; 278 } 279 else if ((baseFormat == GL_RGBA || 280 baseFormat == GL_RGB || 281 baseFormat == GL_RG) && 282 (destBaseFormat == GL_LUMINANCE || 283 destBaseFormat == GL_LUMINANCE_ALPHA || 284 destBaseFormat == GL_LUMINANCE_INTEGER_EXT || 285 destBaseFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT)) { 286 /* If we're reading back an RGB(A) texture as luminance then we need 287 * to return L=tex(R). Note, that's different from glReadPixels which 288 * returns L=R+G+B. 289 */ 290 rebaseFormat = GL_LUMINANCE_ALPHA; /* this covers GL_LUMINANCE too */ 291 } 292 293 if (rebaseFormat) { 294 _mesa_rebase_rgba_float(width * height, (GLfloat (*)[4]) tempImage, 295 rebaseFormat); 296 } 297 298 srcRow = tempImage; 299 for (row = 0; row < height; row++) { 300 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 301 width, height, format, type, 302 0, row, 0); 303 304 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) srcRow, 305 format, type, dest, &ctx->Pack, transferOps); 306 srcRow += width * 4; 307 } 308 309 free(tempImage); 310 } 311 312 313 /** 314 * Get an uncompressed color texture image. 315 */ 316 static void 317 get_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions, 318 GLenum format, GLenum type, GLvoid *pixels, 319 struct gl_texture_image *texImage, 320 GLbitfield transferOps) 321 { 322 /* don't want to apply sRGB -> RGB conversion here so override the format */ 323 const gl_format texFormat = 324 _mesa_get_srgb_format_linear(texImage->TexFormat); 325 const GLuint width = texImage->Width; 326 const GLenum destBaseFormat = _mesa_base_tex_format(ctx, format); 327 GLenum rebaseFormat = GL_NONE; 328 GLuint height = texImage->Height; 329 GLuint depth = texImage->Depth; 330 GLuint img, row; 331 GLfloat (*rgba)[4]; 332 GLuint (*rgba_uint)[4]; 333 GLboolean tex_is_integer = _mesa_is_format_integer_color(texImage->TexFormat); 334 GLboolean tex_is_uint = _mesa_is_format_unsigned(texImage->TexFormat); 335 336 /* Allocate buffer for one row of texels */ 337 rgba = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat)); 338 rgba_uint = (GLuint (*)[4]) rgba; 339 if (!rgba) { 340 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); 341 return; 342 } 343 344 if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) { 345 depth = height; 346 height = 1; 347 } 348 349 if (texImage->_BaseFormat == GL_LUMINANCE || 350 texImage->_BaseFormat == GL_INTENSITY || 351 texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { 352 /* If a luminance (or intensity) texture is read back as RGB(A), the 353 * returned value should be (L,0,0,1), not (L,L,L,1). Set rebaseFormat 354 * here to get G=B=0. 355 */ 356 rebaseFormat = texImage->_BaseFormat; 357 } 358 else if ((texImage->_BaseFormat == GL_RGBA || 359 texImage->_BaseFormat == GL_RGB || 360 texImage->_BaseFormat == GL_RG) && 361 (destBaseFormat == GL_LUMINANCE || 362 destBaseFormat == GL_LUMINANCE_ALPHA || 363 destBaseFormat == GL_LUMINANCE_INTEGER_EXT || 364 destBaseFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT)) { 365 /* If we're reading back an RGB(A) texture as luminance then we need 366 * to return L=tex(R). Note, that's different from glReadPixels which 367 * returns L=R+G+B. 368 */ 369 rebaseFormat = GL_LUMINANCE_ALPHA; /* this covers GL_LUMINANCE too */ 370 } 371 372 for (img = 0; img < depth; img++) { 373 GLubyte *srcMap; 374 GLint rowstride; 375 376 /* map src texture buffer */ 377 ctx->Driver.MapTextureImage(ctx, texImage, img, 378 0, 0, width, height, GL_MAP_READ_BIT, 379 &srcMap, &rowstride); 380 if (srcMap) { 381 for (row = 0; row < height; row++) { 382 const GLubyte *src = srcMap + row * rowstride; 383 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 384 width, height, format, type, 385 img, row, 0); 386 387 if (tex_is_integer) { 388 _mesa_unpack_uint_rgba_row(texFormat, width, src, rgba_uint); 389 if (rebaseFormat) 390 _mesa_rebase_rgba_uint(width, rgba_uint, rebaseFormat); 391 if (tex_is_uint) { 392 _mesa_pack_rgba_span_from_uints(ctx, width, 393 (GLuint (*)[4]) rgba_uint, 394 format, type, dest); 395 } else { 396 _mesa_pack_rgba_span_from_ints(ctx, width, 397 (GLint (*)[4]) rgba_uint, 398 format, type, dest); 399 } 400 } else { 401 _mesa_unpack_rgba_row(texFormat, width, src, rgba); 402 if (rebaseFormat) 403 _mesa_rebase_rgba_float(width, rgba, rebaseFormat); 404 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, 405 format, type, dest, 406 &ctx->Pack, transferOps); 407 } 408 } 409 410 /* Unmap the src texture buffer */ 411 ctx->Driver.UnmapTextureImage(ctx, texImage, img); 412 } 413 else { 414 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 415 break; 416 } 417 } 418 419 free(rgba); 420 } 421 422 423 /** 424 * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc). 425 * Compressed textures are handled here as well. 426 */ 427 static void 428 get_tex_rgba(struct gl_context *ctx, GLuint dimensions, 429 GLenum format, GLenum type, GLvoid *pixels, 430 struct gl_texture_image *texImage) 431 { 432 const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat); 433 GLbitfield transferOps = 0x0; 434 435 /* In general, clamping does not apply to glGetTexImage, except when 436 * the returned type of the image can't hold negative values. 437 */ 438 if (type_needs_clamping(type)) { 439 /* the returned image type can't have negative values */ 440 if (dataType == GL_FLOAT || 441 dataType == GL_SIGNED_NORMALIZED || 442 format == GL_LUMINANCE || 443 format == GL_LUMINANCE_ALPHA) { 444 transferOps |= IMAGE_CLAMP_BIT; 445 } 446 } 447 448 if (_mesa_is_format_compressed(texImage->TexFormat)) { 449 get_tex_rgba_compressed(ctx, dimensions, format, type, 450 pixels, texImage, transferOps); 451 } 452 else { 453 get_tex_rgba_uncompressed(ctx, dimensions, format, type, 454 pixels, texImage, transferOps); 455 } 456 } 457 458 459 /** 460 * Try to do glGetTexImage() with simple memcpy(). 461 * \return GL_TRUE if done, GL_FALSE otherwise 462 */ 463 static GLboolean 464 get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type, 465 GLvoid *pixels, 466 struct gl_texture_image *texImage) 467 { 468 const GLenum target = texImage->TexObject->Target; 469 GLboolean memCopy = GL_FALSE; 470 471 /* 472 * Check if we can use memcpy to copy from the hardware texture 473 * format to the user's format/type. 474 * Note that GL's pixel transfer ops don't apply to glGetTexImage() 475 */ 476 if (target == GL_TEXTURE_1D || 477 target == GL_TEXTURE_2D || 478 target == GL_TEXTURE_RECTANGLE || 479 _mesa_is_cube_face(target)) { 480 memCopy = _mesa_format_matches_format_and_type(texImage->TexFormat, 481 format, type, 482 ctx->Pack.SwapBytes); 483 } 484 485 if (memCopy) { 486 const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat); 487 const GLuint bytesPerRow = texImage->Width * bpp; 488 GLubyte *dst = 489 _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width, 490 texImage->Height, format, type, 0, 0); 491 const GLint dstRowStride = 492 _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type); 493 GLubyte *src; 494 GLint srcRowStride; 495 496 /* map src texture buffer */ 497 ctx->Driver.MapTextureImage(ctx, texImage, 0, 498 0, 0, texImage->Width, texImage->Height, 499 GL_MAP_READ_BIT, &src, &srcRowStride); 500 501 if (src) { 502 if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) { 503 memcpy(dst, src, bytesPerRow * texImage->Height); 504 } 505 else { 506 GLuint row; 507 for (row = 0; row < texImage->Height; row++) { 508 memcpy(dst, src, bytesPerRow); 509 dst += dstRowStride; 510 src += srcRowStride; 511 } 512 } 513 514 /* unmap src texture buffer */ 515 ctx->Driver.UnmapTextureImage(ctx, texImage, 0); 516 } 517 else { 518 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 519 } 520 } 521 522 return memCopy; 523 } 524 525 526 /** 527 * This is the software fallback for Driver.GetTexImage(). 528 * All error checking will have been done before this routine is called. 529 * We'll call ctx->Driver.MapTextureImage() to access the data, then 530 * unmap with ctx->Driver.UnmapTextureImage(). 531 */ 532 void 533 _mesa_get_teximage(struct gl_context *ctx, 534 GLenum format, GLenum type, GLvoid *pixels, 535 struct gl_texture_image *texImage) 536 { 537 GLuint dimensions; 538 539 switch (texImage->TexObject->Target) { 540 case GL_TEXTURE_1D: 541 dimensions = 1; 542 break; 543 case GL_TEXTURE_3D: 544 dimensions = 3; 545 break; 546 default: 547 dimensions = 2; 548 } 549 550 /* map dest buffer, if PBO */ 551 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 552 /* Packing texture image into a PBO. 553 * Map the (potentially) VRAM-based buffer into our process space so 554 * we can write into it with the code below. 555 * A hardware driver might use a sophisticated blit to move the 556 * texture data to the PBO if the PBO is in VRAM along with the texture. 557 */ 558 GLubyte *buf = (GLubyte *) 559 ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size, 560 GL_MAP_WRITE_BIT, ctx->Pack.BufferObj); 561 if (!buf) { 562 /* out of memory or other unexpected error */ 563 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)"); 564 return; 565 } 566 /* <pixels> was an offset into the PBO. 567 * Now make it a real, client-side pointer inside the mapped region. 568 */ 569 pixels = ADD_POINTERS(buf, pixels); 570 } 571 572 if (get_tex_memcpy(ctx, format, type, pixels, texImage)) { 573 /* all done */ 574 } 575 else if (format == GL_DEPTH_COMPONENT) { 576 get_tex_depth(ctx, dimensions, format, type, pixels, texImage); 577 } 578 else if (format == GL_DEPTH_STENCIL_EXT) { 579 get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage); 580 } 581 else if (format == GL_YCBCR_MESA) { 582 get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage); 583 } 584 else { 585 get_tex_rgba(ctx, dimensions, format, type, pixels, texImage); 586 } 587 588 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 589 ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj); 590 } 591 } 592 593 594 595 /** 596 * This is the software fallback for Driver.GetCompressedTexImage(). 597 * All error checking will have been done before this routine is called. 598 */ 599 void 600 _mesa_get_compressed_teximage(struct gl_context *ctx, 601 struct gl_texture_image *texImage, 602 GLvoid *img) 603 { 604 const GLuint row_stride = 605 _mesa_format_row_stride(texImage->TexFormat, texImage->Width); 606 GLuint i; 607 GLubyte *src; 608 GLint srcRowStride; 609 610 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 611 /* pack texture image into a PBO */ 612 GLubyte *buf = (GLubyte *) 613 ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size, 614 GL_MAP_WRITE_BIT, ctx->Pack.BufferObj); 615 if (!buf) { 616 /* out of memory or other unexpected error */ 617 _mesa_error(ctx, GL_OUT_OF_MEMORY, 618 "glGetCompresssedTexImage(map PBO failed)"); 619 return; 620 } 621 img = ADD_POINTERS(buf, img); 622 } 623 624 /* map src texture buffer */ 625 ctx->Driver.MapTextureImage(ctx, texImage, 0, 626 0, 0, texImage->Width, texImage->Height, 627 GL_MAP_READ_BIT, &src, &srcRowStride); 628 629 if (src) { 630 /* no pixelstore or pixel transfer, but respect stride */ 631 632 if (row_stride == srcRowStride) { 633 const GLuint size = _mesa_format_image_size(texImage->TexFormat, 634 texImage->Width, 635 texImage->Height, 636 texImage->Depth); 637 memcpy(img, src, size); 638 } 639 else { 640 GLuint bw, bh; 641 _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh); 642 for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) { 643 memcpy((GLubyte *)img + i * row_stride, 644 (GLubyte *)src + i * srcRowStride, 645 row_stride); 646 } 647 } 648 649 ctx->Driver.UnmapTextureImage(ctx, texImage, 0); 650 } 651 else { 652 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage"); 653 } 654 655 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 656 ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj); 657 } 658 } 659 660 661 /** 662 * Validate the texture target enum supplied to glTexImage or 663 * glCompressedTexImage. 664 */ 665 static GLboolean 666 legal_getteximage_target(struct gl_context *ctx, GLenum target) 667 { 668 switch (target) { 669 case GL_TEXTURE_1D: 670 case GL_TEXTURE_2D: 671 case GL_TEXTURE_3D: 672 return GL_TRUE; 673 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: 674 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: 675 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: 676 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: 677 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: 678 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: 679 return ctx->Extensions.ARB_texture_cube_map; 680 case GL_TEXTURE_RECTANGLE_NV: 681 return ctx->Extensions.NV_texture_rectangle; 682 case GL_TEXTURE_1D_ARRAY_EXT: 683 case GL_TEXTURE_2D_ARRAY_EXT: 684 return (ctx->Extensions.MESA_texture_array || 685 ctx->Extensions.EXT_texture_array); 686 default: 687 return GL_FALSE; 688 } 689 } 690 691 692 /** 693 * Do error checking for a glGetTexImage() call. 694 * \return GL_TRUE if any error, GL_FALSE if no errors. 695 */ 696 static GLboolean 697 getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level, 698 GLenum format, GLenum type, GLsizei clientMemSize, 699 GLvoid *pixels ) 700 { 701 struct gl_texture_object *texObj; 702 struct gl_texture_image *texImage; 703 const GLint maxLevels = _mesa_max_texture_levels(ctx, target); 704 const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; 705 GLenum baseFormat, err; 706 707 if (!legal_getteximage_target(ctx, target)) { 708 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target); 709 return GL_TRUE; 710 } 711 712 assert(maxLevels != 0); 713 if (level < 0 || level >= maxLevels) { 714 _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" ); 715 return GL_TRUE; 716 } 717 718 err = _mesa_error_check_format_and_type(ctx, format, type); 719 if (err != GL_NO_ERROR) { 720 _mesa_error(ctx, err, "glGetTexImage(format/type)"); 721 return GL_TRUE; 722 } 723 724 texObj = _mesa_get_current_tex_object(ctx, target); 725 726 if (!texObj) { 727 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)"); 728 return GL_TRUE; 729 } 730 731 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 732 if (!texImage) { 733 /* non-existant texture image */ 734 return GL_TRUE; 735 } 736 737 baseFormat = _mesa_get_format_base_format(texImage->TexFormat); 738 739 /* Make sure the requested image format is compatible with the 740 * texture's format. 741 */ 742 if (_mesa_is_color_format(format) 743 && !_mesa_is_color_format(baseFormat)) { 744 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 745 return GL_TRUE; 746 } 747 else if (_mesa_is_depth_format(format) 748 && !_mesa_is_depth_format(baseFormat) 749 && !_mesa_is_depthstencil_format(baseFormat)) { 750 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 751 return GL_TRUE; 752 } 753 else if (_mesa_is_ycbcr_format(format) 754 && !_mesa_is_ycbcr_format(baseFormat)) { 755 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 756 return GL_TRUE; 757 } 758 else if (_mesa_is_depthstencil_format(format) 759 && !_mesa_is_depthstencil_format(baseFormat)) { 760 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 761 return GL_TRUE; 762 } 763 else if (_mesa_is_dudv_format(format) 764 && !_mesa_is_dudv_format(baseFormat)) { 765 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 766 return GL_TRUE; 767 } 768 769 if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width, 770 texImage->Height, texImage->Depth, 771 format, type, clientMemSize, pixels)) { 772 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 773 _mesa_error(ctx, GL_INVALID_OPERATION, 774 "glGetTexImage(out of bounds PBO access)"); 775 } else { 776 _mesa_error(ctx, GL_INVALID_OPERATION, 777 "glGetnTexImageARB(out of bounds access:" 778 " bufSize (%d) is too small)", clientMemSize); 779 } 780 return GL_TRUE; 781 } 782 783 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 784 /* PBO should not be mapped */ 785 if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { 786 _mesa_error(ctx, GL_INVALID_OPERATION, 787 "glGetTexImage(PBO is mapped)"); 788 return GL_TRUE; 789 } 790 } 791 792 return GL_FALSE; 793 } 794 795 796 797 /** 798 * Get texture image. Called by glGetTexImage. 799 * 800 * \param target texture target. 801 * \param level image level. 802 * \param format pixel data format for returned image. 803 * \param type pixel data type for returned image. 804 * \param bufSize size of the pixels data buffer. 805 * \param pixels returned pixel data. 806 */ 807 void GLAPIENTRY 808 _mesa_GetnTexImageARB( GLenum target, GLint level, GLenum format, 809 GLenum type, GLsizei bufSize, GLvoid *pixels ) 810 { 811 struct gl_texture_object *texObj; 812 struct gl_texture_image *texImage; 813 GET_CURRENT_CONTEXT(ctx); 814 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 815 816 if (getteximage_error_check(ctx, target, level, format, type, 817 bufSize, pixels)) { 818 return; 819 } 820 821 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) { 822 /* not an error, do nothing */ 823 return; 824 } 825 826 texObj = _mesa_get_current_tex_object(ctx, target); 827 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 828 829 if (_mesa_is_zero_size_texture(texImage)) 830 return; 831 832 if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { 833 _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d," 834 " dstFmt=0x%x, dstType=0x%x\n", 835 texObj->Name, 836 _mesa_get_format_name(texImage->TexFormat), 837 texImage->Width, texImage->Height, 838 format, type); 839 } 840 841 _mesa_lock_texture(ctx, texObj); 842 { 843 ctx->Driver.GetTexImage(ctx, format, type, pixels, texImage); 844 } 845 _mesa_unlock_texture(ctx, texObj); 846 } 847 848 849 void GLAPIENTRY 850 _mesa_GetTexImage( GLenum target, GLint level, GLenum format, 851 GLenum type, GLvoid *pixels ) 852 { 853 _mesa_GetnTexImageARB(target, level, format, type, INT_MAX, pixels); 854 } 855 856 857 /** 858 * Do error checking for a glGetCompressedTexImage() call. 859 * \return GL_TRUE if any error, GL_FALSE if no errors. 860 */ 861 static GLboolean 862 getcompressedteximage_error_check(struct gl_context *ctx, GLenum target, 863 GLint level, GLsizei clientMemSize, GLvoid *img) 864 { 865 struct gl_texture_object *texObj; 866 struct gl_texture_image *texImage; 867 const GLint maxLevels = _mesa_max_texture_levels(ctx, target); 868 GLuint compressedSize; 869 870 if (!legal_getteximage_target(ctx, target)) { 871 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)", 872 target); 873 return GL_TRUE; 874 } 875 876 assert(maxLevels != 0); 877 if (level < 0 || level >= maxLevels) { 878 _mesa_error(ctx, GL_INVALID_VALUE, 879 "glGetCompressedTexImageARB(bad level = %d)", level); 880 return GL_TRUE; 881 } 882 883 texObj = _mesa_get_current_tex_object(ctx, target); 884 if (!texObj) { 885 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)"); 886 return GL_TRUE; 887 } 888 889 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 890 891 if (!texImage) { 892 /* probably invalid mipmap level */ 893 _mesa_error(ctx, GL_INVALID_VALUE, 894 "glGetCompressedTexImageARB(level)"); 895 return GL_TRUE; 896 } 897 898 if (!_mesa_is_format_compressed(texImage->TexFormat)) { 899 _mesa_error(ctx, GL_INVALID_OPERATION, 900 "glGetCompressedTexImageARB(texture is not compressed)"); 901 return GL_TRUE; 902 } 903 904 compressedSize = _mesa_format_image_size(texImage->TexFormat, 905 texImage->Width, 906 texImage->Height, 907 texImage->Depth); 908 909 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 910 /* do bounds checking on writing to client memory */ 911 if (clientMemSize < compressedSize) { 912 _mesa_error(ctx, GL_INVALID_OPERATION, 913 "glGetnCompressedTexImageARB(out of bounds access:" 914 " bufSize (%d) is too small)", clientMemSize); 915 return GL_TRUE; 916 } 917 } else { 918 /* do bounds checking on PBO write */ 919 if ((const GLubyte *) img + compressedSize > 920 (const GLubyte *) ctx->Pack.BufferObj->Size) { 921 _mesa_error(ctx, GL_INVALID_OPERATION, 922 "glGetCompressedTexImage(out of bounds PBO access)"); 923 return GL_TRUE; 924 } 925 926 /* make sure PBO is not mapped */ 927 if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { 928 _mesa_error(ctx, GL_INVALID_OPERATION, 929 "glGetCompressedTexImage(PBO is mapped)"); 930 return GL_TRUE; 931 } 932 } 933 934 return GL_FALSE; 935 } 936 937 938 void GLAPIENTRY 939 _mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize, 940 GLvoid *img) 941 { 942 struct gl_texture_object *texObj; 943 struct gl_texture_image *texImage; 944 GET_CURRENT_CONTEXT(ctx); 945 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 946 947 if (getcompressedteximage_error_check(ctx, target, level, bufSize, img)) { 948 return; 949 } 950 951 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) { 952 /* not an error, do nothing */ 953 return; 954 } 955 956 texObj = _mesa_get_current_tex_object(ctx, target); 957 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 958 959 if (_mesa_is_zero_size_texture(texImage)) 960 return; 961 962 if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { 963 _mesa_debug(ctx, 964 "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n", 965 texObj->Name, 966 _mesa_get_format_name(texImage->TexFormat), 967 texImage->Width, texImage->Height); 968 } 969 970 _mesa_lock_texture(ctx, texObj); 971 { 972 ctx->Driver.GetCompressedTexImage(ctx, texImage, img); 973 } 974 _mesa_unlock_texture(ctx, texObj); 975 } 976 977 void GLAPIENTRY 978 _mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img) 979 { 980 _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img); 981 } 982