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