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