texgetimage.c revision 12d924c5ae14a1c6a05a3dcae29b77e7668e227d
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_WRITE_ONLY_ARB, ctx->Pack.BufferObj); 445 if (!buf) { 446 /* out of memory or other unexpected error */ 447 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)"); 448 return; 449 } 450 /* <pixels> was an offset into the PBO. 451 * Now make it a real, client-side pointer inside the mapped region. 452 */ 453 pixels = ADD_POINTERS(buf, pixels); 454 } 455 456 if (get_tex_memcpy(ctx, format, type, pixels, texObj, texImage)) { 457 /* all done */ 458 } 459 else if (format == GL_COLOR_INDEX) { 460 get_tex_color_index(ctx, dimensions, format, type, pixels, texImage); 461 } 462 else if (format == GL_DEPTH_COMPONENT) { 463 get_tex_depth(ctx, dimensions, format, type, pixels, texImage); 464 } 465 else if (format == GL_DEPTH_STENCIL_EXT) { 466 get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage); 467 } 468 else if (format == GL_YCBCR_MESA) { 469 get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage); 470 } 471 else { 472 get_tex_rgba(ctx, dimensions, format, type, pixels, texImage); 473 } 474 475 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 476 ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj); 477 } 478} 479 480 481 482/** 483 * This is the software fallback for Driver.GetCompressedTexImage(). 484 * All error checking will have been done before this routine is called. 485 */ 486void 487_mesa_get_compressed_teximage(struct gl_context *ctx, GLenum target, GLint level, 488 GLvoid *img, 489 struct gl_texture_object *texObj, 490 struct gl_texture_image *texImage) 491{ 492 const GLuint row_stride = _mesa_format_row_stride(texImage->TexFormat, 493 texImage->Width); 494 const GLuint row_stride_stored = _mesa_format_row_stride(texImage->TexFormat, 495 texImage->RowStride); 496 GLuint i; 497 498 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 499 /* pack texture image into a PBO */ 500 GLubyte *buf = (GLubyte *) 501 ctx->Driver.MapBuffer(ctx, GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj); 502 if (!buf) { 503 /* out of memory or other unexpected error */ 504 _mesa_error(ctx, GL_OUT_OF_MEMORY, 505 "glGetCompresssedTexImage(map PBO failed)"); 506 return; 507 } 508 img = ADD_POINTERS(buf, img); 509 } 510 511 /* no pixelstore or pixel transfer, but respect stride */ 512 513 if (row_stride == row_stride_stored) { 514 const GLuint size = _mesa_format_image_size(texImage->TexFormat, 515 texImage->Width, 516 texImage->Height, 517 texImage->Depth); 518 memcpy(img, texImage->Data, size); 519 } 520 else { 521 GLuint bw, bh; 522 _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh); 523 for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) { 524 memcpy((GLubyte *)img + i * row_stride, 525 (GLubyte *)texImage->Data + i * row_stride_stored, 526 row_stride); 527 } 528 } 529 530 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 531 ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj); 532 } 533} 534 535 536 537/** 538 * Do error checking for a glGetTexImage() call. 539 * \return GL_TRUE if any error, GL_FALSE if no errors. 540 */ 541static GLboolean 542getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level, 543 GLenum format, GLenum type, GLsizei clientMemSize, 544 GLvoid *pixels ) 545{ 546 struct gl_texture_object *texObj; 547 struct gl_texture_image *texImage; 548 const GLint maxLevels = _mesa_max_texture_levels(ctx, target); 549 const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; 550 GLenum baseFormat; 551 552 if (maxLevels == 0) { 553 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target); 554 return GL_TRUE; 555 } 556 557 if (level < 0 || level >= maxLevels) { 558 _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" ); 559 return GL_TRUE; 560 } 561 562 if (_mesa_sizeof_packed_type(type) <= 0) { 563 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" ); 564 return GL_TRUE; 565 } 566 567 if (_mesa_components_in_format(format) <= 0 || 568 format == GL_STENCIL_INDEX) { 569 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" ); 570 return GL_TRUE; 571 } 572 573 if (!ctx->Extensions.EXT_paletted_texture && _mesa_is_index_format(format)) { 574 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); 575 return GL_TRUE; 576 } 577 578 if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) { 579 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); 580 return GL_TRUE; 581 } 582 583 if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) { 584 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); 585 return GL_TRUE; 586 } 587 588 if (!ctx->Extensions.EXT_packed_depth_stencil 589 && _mesa_is_depthstencil_format(format)) { 590 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); 591 return GL_TRUE; 592 } 593 594 if (!ctx->Extensions.ATI_envmap_bumpmap 595 && _mesa_is_dudv_format(format)) { 596 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); 597 return GL_TRUE; 598 } 599 600 texObj = _mesa_get_current_tex_object(ctx, target); 601 602 if (!texObj || _mesa_is_proxy_texture(target)) { 603 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)"); 604 return GL_TRUE; 605 } 606 607 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 608 if (!texImage) { 609 /* out of memory */ 610 return GL_TRUE; 611 } 612 613 baseFormat = _mesa_get_format_base_format(texImage->TexFormat); 614 615 /* Make sure the requested image format is compatible with the 616 * texture's format. Note that a color index texture can be converted 617 * to RGBA so that combo is allowed. 618 */ 619 if (_mesa_is_color_format(format) 620 && !_mesa_is_color_format(baseFormat) 621 && !_mesa_is_index_format(baseFormat)) { 622 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 623 return GL_TRUE; 624 } 625 else if (_mesa_is_index_format(format) 626 && !_mesa_is_index_format(baseFormat)) { 627 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 628 return GL_TRUE; 629 } 630 else if (_mesa_is_depth_format(format) 631 && !_mesa_is_depth_format(baseFormat) 632 && !_mesa_is_depthstencil_format(baseFormat)) { 633 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 634 return GL_TRUE; 635 } 636 else if (_mesa_is_ycbcr_format(format) 637 && !_mesa_is_ycbcr_format(baseFormat)) { 638 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 639 return GL_TRUE; 640 } 641 else if (_mesa_is_depthstencil_format(format) 642 && !_mesa_is_depthstencil_format(baseFormat)) { 643 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 644 return GL_TRUE; 645 } 646 else if (_mesa_is_dudv_format(format) 647 && !_mesa_is_dudv_format(baseFormat)) { 648 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 649 return GL_TRUE; 650 } 651 652 if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width, 653 texImage->Height, texImage->Depth, 654 format, type, clientMemSize, pixels)) { 655 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 656 _mesa_error(ctx, GL_INVALID_OPERATION, 657 "glGetTexImage(out of bounds PBO access)"); 658 } else { 659 _mesa_error(ctx, GL_INVALID_OPERATION, 660 "glGetnTexImageARB(out of bounds access:" 661 " bufSize (%d) is too small)", clientMemSize); 662 } 663 return GL_TRUE; 664 } 665 666 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 667 /* PBO should not be mapped */ 668 if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { 669 _mesa_error(ctx, GL_INVALID_OPERATION, 670 "glGetTexImage(PBO is mapped)"); 671 return GL_TRUE; 672 } 673 } 674 675 return GL_FALSE; 676} 677 678 679 680/** 681 * Get texture image. Called by glGetTexImage. 682 * 683 * \param target texture target. 684 * \param level image level. 685 * \param format pixel data format for returned image. 686 * \param type pixel data type for returned image. 687 * \param bufSize size of the pixels data buffer. 688 * \param pixels returned pixel data. 689 */ 690void GLAPIENTRY 691_mesa_GetnTexImageARB( GLenum target, GLint level, GLenum format, 692 GLenum type, GLsizei bufSize, GLvoid *pixels ) 693{ 694 struct gl_texture_object *texObj; 695 struct gl_texture_image *texImage; 696 GET_CURRENT_CONTEXT(ctx); 697 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 698 699 if (getteximage_error_check(ctx, target, level, format, type, 700 bufSize, pixels)) { 701 return; 702 } 703 704 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) { 705 /* not an error, do nothing */ 706 return; 707 } 708 709 texObj = _mesa_get_current_tex_object(ctx, target); 710 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 711 712 if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { 713 _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d," 714 " dstFmt=0x%x, dstType=0x%x\n", 715 texObj->Name, 716 _mesa_get_format_name(texImage->TexFormat), 717 texImage->Width, texImage->Height, 718 format, type); 719 } 720 721 _mesa_lock_texture(ctx, texObj); 722 { 723 ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels, 724 texObj, texImage); 725 } 726 _mesa_unlock_texture(ctx, texObj); 727} 728 729 730void GLAPIENTRY 731_mesa_GetTexImage( GLenum target, GLint level, GLenum format, 732 GLenum type, GLvoid *pixels ) 733{ 734 _mesa_GetnTexImageARB(target, level, format, type, INT_MAX, pixels); 735} 736 737 738/** 739 * Do error checking for a glGetCompressedTexImage() call. 740 * \return GL_TRUE if any error, GL_FALSE if no errors. 741 */ 742static GLboolean 743getcompressedteximage_error_check(struct gl_context *ctx, GLenum target, 744 GLint level, GLsizei clientMemSize, GLvoid *img) 745{ 746 struct gl_texture_object *texObj; 747 struct gl_texture_image *texImage; 748 const GLint maxLevels = _mesa_max_texture_levels(ctx, target); 749 GLuint compressedSize; 750 751 if (maxLevels == 0) { 752 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)", 753 target); 754 return GL_TRUE; 755 } 756 757 if (level < 0 || level >= maxLevels) { 758 _mesa_error(ctx, GL_INVALID_VALUE, 759 "glGetCompressedTexImageARB(bad level = %d)", level); 760 return GL_TRUE; 761 } 762 763 if (_mesa_is_proxy_texture(target)) { 764 _mesa_error(ctx, GL_INVALID_ENUM, 765 "glGetCompressedTexImageARB(bad target = %s)", 766 _mesa_lookup_enum_by_nr(target)); 767 return GL_TRUE; 768 } 769 770 texObj = _mesa_get_current_tex_object(ctx, target); 771 if (!texObj) { 772 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)"); 773 return GL_TRUE; 774 } 775 776 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 777 778 if (!texImage) { 779 /* probably invalid mipmap level */ 780 _mesa_error(ctx, GL_INVALID_VALUE, 781 "glGetCompressedTexImageARB(level)"); 782 return GL_TRUE; 783 } 784 785 if (!_mesa_is_format_compressed(texImage->TexFormat)) { 786 _mesa_error(ctx, GL_INVALID_OPERATION, 787 "glGetCompressedTexImageARB(texture is not compressed)"); 788 return GL_TRUE; 789 } 790 791 compressedSize = _mesa_format_image_size(texImage->TexFormat, 792 texImage->Width, 793 texImage->Height, 794 texImage->Depth); 795 796 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 797 /* do bounds checking on writing to client memory */ 798 if (clientMemSize < compressedSize) { 799 _mesa_error(ctx, GL_INVALID_OPERATION, 800 "glGetnCompressedTexImageARB(out of bounds access:" 801 " bufSize (%d) is too small)", clientMemSize); 802 } 803 } else { 804 /* do bounds checking on PBO write */ 805 if ((const GLubyte *) img + compressedSize > 806 (const GLubyte *) ctx->Pack.BufferObj->Size) { 807 _mesa_error(ctx, GL_INVALID_OPERATION, 808 "glGetCompressedTexImage(out of bounds PBO access)"); 809 return GL_TRUE; 810 } 811 812 /* make sure PBO is not mapped */ 813 if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { 814 _mesa_error(ctx, GL_INVALID_OPERATION, 815 "glGetCompressedTexImage(PBO is mapped)"); 816 return GL_TRUE; 817 } 818 } 819 820 return GL_FALSE; 821} 822 823 824void GLAPIENTRY 825_mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize, 826 GLvoid *img) 827{ 828 struct gl_texture_object *texObj; 829 struct gl_texture_image *texImage; 830 GET_CURRENT_CONTEXT(ctx); 831 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 832 833 if (getcompressedteximage_error_check(ctx, target, level, bufSize, img)) { 834 return; 835 } 836 837 if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) { 838 /* not an error, do nothing */ 839 return; 840 } 841 842 texObj = _mesa_get_current_tex_object(ctx, target); 843 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 844 845 if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { 846 _mesa_debug(ctx, 847 "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n", 848 texObj->Name, 849 _mesa_get_format_name(texImage->TexFormat), 850 texImage->Width, texImage->Height); 851 } 852 853 _mesa_lock_texture(ctx, texObj); 854 { 855 ctx->Driver.GetCompressedTexImage(ctx, target, level, img, 856 texObj, texImage); 857 } 858 _mesa_unlock_texture(ctx, texObj); 859} 860 861void GLAPIENTRY 862_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img) 863{ 864 _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img); 865} 866