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