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