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