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