readpix.c revision 7ef270867cb1f3e19067c93449e48987a32730d3
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.1 4 * 5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25#include "glheader.h" 26#include "imports.h" 27#include "bufferobj.h" 28#include "context.h" 29#include "enums.h" 30#include "readpix.h" 31#include "framebuffer.h" 32#include "formats.h" 33#include "format_unpack.h" 34#include "image.h" 35#include "mtypes.h" 36#include "pack.h" 37#include "pbo.h" 38#include "state.h" 39#include "glformats.h" 40#include "fbobject.h" 41 42 43/** 44 * Tries to implement glReadPixels() of GL_DEPTH_COMPONENT using memcpy of the 45 * mapping. 46 */ 47static GLboolean 48fast_read_depth_pixels( struct gl_context *ctx, 49 GLint x, GLint y, 50 GLsizei width, GLsizei height, 51 GLenum type, GLvoid *pixels, 52 const struct gl_pixelstore_attrib *packing ) 53{ 54 struct gl_framebuffer *fb = ctx->ReadBuffer; 55 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; 56 GLubyte *map, *dst; 57 int stride, dstStride, j; 58 59 if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0) 60 return GL_FALSE; 61 62 if (packing->SwapBytes) 63 return GL_FALSE; 64 65 if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED) 66 return GL_FALSE; 67 68 if (!((type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16) || 69 type == GL_UNSIGNED_INT)) 70 return GL_FALSE; 71 72 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, 73 &map, &stride); 74 75 if (!map) { 76 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 77 return GL_TRUE; /* don't bother trying the slow path */ 78 } 79 80 dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type); 81 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, 82 GL_DEPTH_COMPONENT, type, 0, 0); 83 84 for (j = 0; j < height; j++) { 85 if (type == GL_UNSIGNED_INT) { 86 _mesa_unpack_uint_z_row(rb->Format, width, map, (GLuint *)dst); 87 } else { 88 ASSERT(type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16); 89 memcpy(dst, map, width * 2); 90 } 91 92 map += stride; 93 dst += dstStride; 94 } 95 ctx->Driver.UnmapRenderbuffer(ctx, rb); 96 97 return GL_TRUE; 98} 99 100/** 101 * Read pixels for format=GL_DEPTH_COMPONENT. 102 */ 103static void 104read_depth_pixels( struct gl_context *ctx, 105 GLint x, GLint y, 106 GLsizei width, GLsizei height, 107 GLenum type, GLvoid *pixels, 108 const struct gl_pixelstore_attrib *packing ) 109{ 110 struct gl_framebuffer *fb = ctx->ReadBuffer; 111 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; 112 GLint j; 113 GLubyte *dst, *map; 114 int dstStride, stride; 115 GLfloat *depthValues; 116 117 if (!rb) 118 return; 119 120 /* clipping should have been done already */ 121 ASSERT(x >= 0); 122 ASSERT(y >= 0); 123 ASSERT(x + width <= (GLint) rb->Width); 124 ASSERT(y + height <= (GLint) rb->Height); 125 126 if (fast_read_depth_pixels(ctx, x, y, width, height, type, pixels, packing)) 127 return; 128 129 dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type); 130 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, 131 GL_DEPTH_COMPONENT, type, 0, 0); 132 133 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, 134 &map, &stride); 135 if (!map) { 136 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 137 return; 138 } 139 140 depthValues = (GLfloat *) malloc(width * sizeof(GLfloat)); 141 142 if (depthValues) { 143 /* General case (slower) */ 144 for (j = 0; j < height; j++, y++) { 145 _mesa_unpack_float_z_row(rb->Format, width, map, depthValues); 146 _mesa_pack_depth_span(ctx, width, dst, type, depthValues, packing); 147 148 dst += dstStride; 149 map += stride; 150 } 151 } 152 else { 153 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 154 } 155 156 free(depthValues); 157 158 ctx->Driver.UnmapRenderbuffer(ctx, rb); 159} 160 161 162/** 163 * Read pixels for format=GL_STENCIL_INDEX. 164 */ 165static void 166read_stencil_pixels( struct gl_context *ctx, 167 GLint x, GLint y, 168 GLsizei width, GLsizei height, 169 GLenum type, GLvoid *pixels, 170 const struct gl_pixelstore_attrib *packing ) 171{ 172 struct gl_framebuffer *fb = ctx->ReadBuffer; 173 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; 174 GLint j; 175 GLubyte *map, *stencil; 176 GLint stride; 177 178 if (!rb) 179 return; 180 181 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, 182 &map, &stride); 183 if (!map) { 184 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 185 return; 186 } 187 188 stencil = (GLubyte *) malloc(width * sizeof(GLubyte)); 189 190 if (stencil) { 191 /* process image row by row */ 192 for (j = 0; j < height; j++) { 193 GLvoid *dest; 194 195 _mesa_unpack_ubyte_stencil_row(rb->Format, width, map, stencil); 196 dest = _mesa_image_address2d(packing, pixels, width, height, 197 GL_STENCIL_INDEX, type, j, 0); 198 199 _mesa_pack_stencil_span(ctx, width, type, dest, stencil, packing); 200 201 map += stride; 202 } 203 } 204 else { 205 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 206 } 207 208 free(stencil); 209 210 ctx->Driver.UnmapRenderbuffer(ctx, rb); 211} 212 213 214/** 215 * Try to do glReadPixels of RGBA data using a simple memcpy or swizzle. 216 * \return GL_TRUE if successful, GL_FALSE otherwise (use the slow path) 217 */ 218static GLboolean 219fast_read_rgba_pixels_memcpy( struct gl_context *ctx, 220 GLint x, GLint y, 221 GLsizei width, GLsizei height, 222 GLenum format, GLenum type, 223 GLvoid *pixels, 224 const struct gl_pixelstore_attrib *packing, 225 GLbitfield transferOps ) 226{ 227 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; 228 GLubyte *dst, *map; 229 int dstStride, stride, j, texelBytes; 230 GLboolean swizzle_rb = GL_FALSE, copy_xrgb = GL_FALSE; 231 232 /* XXX we could check for other swizzle/special cases here as needed */ 233 if (rb->Format == MESA_FORMAT_RGBA8888_REV && 234 format == GL_BGRA && 235 type == GL_UNSIGNED_INT_8_8_8_8_REV && 236 !ctx->Pack.SwapBytes) { 237 swizzle_rb = GL_TRUE; 238 } 239 else if (rb->Format == MESA_FORMAT_XRGB8888 && 240 format == GL_BGRA && 241 type == GL_UNSIGNED_INT_8_8_8_8_REV && 242 !ctx->Pack.SwapBytes) { 243 copy_xrgb = GL_TRUE; 244 } 245 else if (!_mesa_format_matches_format_and_type(rb->Format, format, type, 246 ctx->Pack.SwapBytes)) 247 return GL_FALSE; 248 249 /* If the format is unsigned normalized then we can ignore clamping 250 * because the values are already in the range [0,1] so it won't 251 * have any effect anyway. 252 */ 253 if (_mesa_get_format_datatype(rb->Format) == GL_UNSIGNED_NORMALIZED) 254 transferOps &= ~IMAGE_CLAMP_BIT; 255 256 if (transferOps) 257 return GL_FALSE; 258 259 dstStride = _mesa_image_row_stride(packing, width, format, type); 260 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, 261 format, type, 0, 0); 262 263 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, 264 &map, &stride); 265 if (!map) { 266 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 267 return GL_TRUE; /* don't bother trying the slow path */ 268 } 269 270 texelBytes = _mesa_get_format_bytes(rb->Format); 271 272 if (swizzle_rb) { 273 /* swap R/B */ 274 for (j = 0; j < height; j++) { 275 int i; 276 for (i = 0; i < width; i++) { 277 GLuint *dst4 = (GLuint *) dst, *map4 = (GLuint *) map; 278 GLuint pixel = map4[i]; 279 dst4[i] = (pixel & 0xff00ff00) 280 | ((pixel & 0x00ff0000) >> 16) 281 | ((pixel & 0x000000ff) << 16); 282 } 283 dst += dstStride; 284 map += stride; 285 } 286 } else if (copy_xrgb) { 287 /* convert xrgb -> argb */ 288 for (j = 0; j < height; j++) { 289 GLuint *dst4 = (GLuint *) dst, *map4 = (GLuint *) map; 290 int i; 291 for (i = 0; i < width; i++) { 292 dst4[i] = map4[i] | 0xff000000; /* set A=0xff */ 293 } 294 dst += dstStride; 295 map += stride; 296 } 297 } else { 298 /* just memcpy */ 299 for (j = 0; j < height; j++) { 300 memcpy(dst, map, width * texelBytes); 301 dst += dstStride; 302 map += stride; 303 } 304 } 305 306 ctx->Driver.UnmapRenderbuffer(ctx, rb); 307 308 return GL_TRUE; 309} 310 311static void 312slow_read_rgba_pixels( struct gl_context *ctx, 313 GLint x, GLint y, 314 GLsizei width, GLsizei height, 315 GLenum format, GLenum type, 316 GLvoid *pixels, 317 const struct gl_pixelstore_attrib *packing, 318 GLbitfield transferOps ) 319{ 320 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; 321 const gl_format rbFormat = _mesa_get_srgb_format_linear(rb->Format); 322 void *rgba; 323 GLubyte *dst, *map; 324 int dstStride, stride, j; 325 326 dstStride = _mesa_image_row_stride(packing, width, format, type); 327 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, 328 format, type, 0, 0); 329 330 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, 331 &map, &stride); 332 if (!map) { 333 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 334 return; 335 } 336 337 rgba = malloc(width * MAX_PIXEL_BYTES); 338 if (!rgba) 339 goto done; 340 341 for (j = 0; j < height; j++) { 342 if (_mesa_is_enum_format_integer(format)) { 343 _mesa_unpack_uint_rgba_row(rbFormat, width, map, (GLuint (*)[4]) rgba); 344 _mesa_rebase_rgba_uint(width, (GLuint (*)[4]) rgba, 345 rb->_BaseFormat); 346 _mesa_pack_rgba_span_from_uints(ctx, width, (GLuint (*)[4]) rgba, format, 347 type, dst); 348 } else { 349 _mesa_unpack_rgba_row(rbFormat, width, map, (GLfloat (*)[4]) rgba); 350 _mesa_rebase_rgba_float(width, (GLfloat (*)[4]) rgba, 351 rb->_BaseFormat); 352 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, 353 type, dst, packing, transferOps); 354 } 355 dst += dstStride; 356 map += stride; 357 } 358 359 free(rgba); 360 361done: 362 ctx->Driver.UnmapRenderbuffer(ctx, rb); 363} 364 365/* 366 * Read R, G, B, A, RGB, L, or LA pixels. 367 */ 368static void 369read_rgba_pixels( struct gl_context *ctx, 370 GLint x, GLint y, 371 GLsizei width, GLsizei height, 372 GLenum format, GLenum type, GLvoid *pixels, 373 const struct gl_pixelstore_attrib *packing ) 374{ 375 GLbitfield transferOps = ctx->_ImageTransferState; 376 struct gl_framebuffer *fb = ctx->ReadBuffer; 377 struct gl_renderbuffer *rb = fb->_ColorReadBuffer; 378 379 if (!rb) 380 return; 381 382 if ((ctx->Color._ClampReadColor == GL_TRUE || type != GL_FLOAT) && 383 !_mesa_is_enum_format_integer(format)) { 384 transferOps |= IMAGE_CLAMP_BIT; 385 } 386 387 /* Try the optimized paths first. */ 388 if (fast_read_rgba_pixels_memcpy(ctx, x, y, width, height, 389 format, type, pixels, packing, 390 transferOps)) { 391 return; 392 } 393 394 slow_read_rgba_pixels(ctx, x, y, width, height, 395 format, type, pixels, packing, transferOps); 396} 397 398/** 399 * For a packed depth/stencil buffer being read as depth/stencil, just memcpy the 400 * data (possibly swapping 8/24 vs 24/8 as we go). 401 */ 402static GLboolean 403fast_read_depth_stencil_pixels(struct gl_context *ctx, 404 GLint x, GLint y, 405 GLsizei width, GLsizei height, 406 GLubyte *dst, int dstStride) 407{ 408 struct gl_framebuffer *fb = ctx->ReadBuffer; 409 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; 410 struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; 411 GLubyte *map; 412 int stride, i; 413 414 if (rb != stencilRb) 415 return GL_FALSE; 416 417 if (rb->Format != MESA_FORMAT_Z24_S8 && 418 rb->Format != MESA_FORMAT_S8_Z24) 419 return GL_FALSE; 420 421 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, 422 &map, &stride); 423 if (!map) { 424 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 425 return GL_TRUE; /* don't bother trying the slow path */ 426 } 427 428 for (i = 0; i < height; i++) { 429 _mesa_unpack_uint_24_8_depth_stencil_row(rb->Format, width, 430 map, (GLuint *)dst); 431 map += stride; 432 dst += dstStride; 433 } 434 435 ctx->Driver.UnmapRenderbuffer(ctx, rb); 436 437 return GL_TRUE; 438} 439 440 441/** 442 * For non-float-depth and stencil buffers being read as 24/8 depth/stencil, 443 * copy the integer data directly instead of converting depth to float and 444 * re-packing. 445 */ 446static GLboolean 447fast_read_depth_stencil_pixels_separate(struct gl_context *ctx, 448 GLint x, GLint y, 449 GLsizei width, GLsizei height, 450 uint32_t *dst, int dstStride) 451{ 452 struct gl_framebuffer *fb = ctx->ReadBuffer; 453 struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; 454 struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; 455 GLubyte *depthMap, *stencilMap, *stencilVals; 456 int depthStride, stencilStride, i, j; 457 458 if (_mesa_get_format_datatype(depthRb->Format) != GL_UNSIGNED_NORMALIZED) 459 return GL_FALSE; 460 461 ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height, 462 GL_MAP_READ_BIT, &depthMap, &depthStride); 463 if (!depthMap) { 464 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 465 return GL_TRUE; /* don't bother trying the slow path */ 466 } 467 468 ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height, 469 GL_MAP_READ_BIT, &stencilMap, &stencilStride); 470 if (!stencilMap) { 471 ctx->Driver.UnmapRenderbuffer(ctx, depthRb); 472 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 473 return GL_TRUE; /* don't bother trying the slow path */ 474 } 475 476 stencilVals = (GLubyte *) malloc(width * sizeof(GLubyte)); 477 478 if (stencilVals) { 479 for (j = 0; j < height; j++) { 480 _mesa_unpack_uint_z_row(depthRb->Format, width, depthMap, dst); 481 _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width, 482 stencilMap, stencilVals); 483 484 for (i = 0; i < width; i++) { 485 dst[i] = (dst[i] & 0xffffff00) | stencilVals[i]; 486 } 487 488 depthMap += depthStride; 489 stencilMap += stencilStride; 490 dst += dstStride / 4; 491 } 492 } 493 else { 494 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 495 } 496 497 free(stencilVals); 498 499 ctx->Driver.UnmapRenderbuffer(ctx, depthRb); 500 ctx->Driver.UnmapRenderbuffer(ctx, stencilRb); 501 502 return GL_TRUE; 503} 504 505static void 506slow_read_depth_stencil_pixels_separate(struct gl_context *ctx, 507 GLint x, GLint y, 508 GLsizei width, GLsizei height, 509 GLenum type, 510 const struct gl_pixelstore_attrib *packing, 511 GLubyte *dst, int dstStride) 512{ 513 struct gl_framebuffer *fb = ctx->ReadBuffer; 514 struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; 515 struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; 516 GLubyte *depthMap, *stencilMap; 517 int depthStride, stencilStride, j; 518 GLubyte *stencilVals; 519 GLfloat *depthVals; 520 521 522 /* The depth and stencil buffers might be separate, or a single buffer. 523 * If one buffer, only map it once. 524 */ 525 ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height, 526 GL_MAP_READ_BIT, &depthMap, &depthStride); 527 if (!depthMap) { 528 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 529 return; 530 } 531 532 if (stencilRb != depthRb) { 533 ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height, 534 GL_MAP_READ_BIT, &stencilMap, 535 &stencilStride); 536 if (!stencilMap) { 537 ctx->Driver.UnmapRenderbuffer(ctx, depthRb); 538 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 539 return; 540 } 541 } 542 else { 543 stencilMap = depthMap; 544 stencilStride = depthStride; 545 } 546 547 stencilVals = (GLubyte *) malloc(width * sizeof(GLubyte)); 548 depthVals = (GLfloat *) malloc(width * sizeof(GLfloat)); 549 550 if (stencilVals && depthVals) { 551 for (j = 0; j < height; j++) { 552 _mesa_unpack_float_z_row(depthRb->Format, width, depthMap, depthVals); 553 _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width, 554 stencilMap, stencilVals); 555 556 _mesa_pack_depth_stencil_span(ctx, width, type, (GLuint *)dst, 557 depthVals, stencilVals, packing); 558 559 depthMap += depthStride; 560 stencilMap += stencilStride; 561 dst += dstStride; 562 } 563 } 564 else { 565 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 566 } 567 568 free(stencilVals); 569 free(depthVals); 570 571 ctx->Driver.UnmapRenderbuffer(ctx, depthRb); 572 if (stencilRb != depthRb) { 573 ctx->Driver.UnmapRenderbuffer(ctx, stencilRb); 574 } 575} 576 577 578/** 579 * Read combined depth/stencil values. 580 * We'll have already done error checking to be sure the expected 581 * depth and stencil buffers really exist. 582 */ 583static void 584read_depth_stencil_pixels(struct gl_context *ctx, 585 GLint x, GLint y, 586 GLsizei width, GLsizei height, 587 GLenum type, GLvoid *pixels, 588 const struct gl_pixelstore_attrib *packing ) 589{ 590 const GLboolean scaleOrBias 591 = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; 592 const GLboolean stencilTransfer = ctx->Pixel.IndexShift 593 || ctx->Pixel.IndexOffset || ctx->Pixel.MapStencilFlag; 594 GLubyte *dst; 595 int dstStride; 596 597 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, 598 width, height, 599 GL_DEPTH_STENCIL_EXT, 600 type, 0, 0); 601 dstStride = _mesa_image_row_stride(packing, width, 602 GL_DEPTH_STENCIL_EXT, type); 603 604 /* Fast 24/8 reads. */ 605 if (type == GL_UNSIGNED_INT_24_8 && 606 !scaleOrBias && !stencilTransfer && !packing->SwapBytes) { 607 if (fast_read_depth_stencil_pixels(ctx, x, y, width, height, 608 dst, dstStride)) 609 return; 610 611 if (fast_read_depth_stencil_pixels_separate(ctx, x, y, width, height, 612 (uint32_t *)dst, dstStride)) 613 return; 614 } 615 616 slow_read_depth_stencil_pixels_separate(ctx, x, y, width, height, 617 type, packing, 618 dst, dstStride); 619} 620 621 622 623/** 624 * Software fallback routine for ctx->Driver.ReadPixels(). 625 * By time we get here, all error checking will have been done. 626 */ 627void 628_mesa_readpixels(struct gl_context *ctx, 629 GLint x, GLint y, GLsizei width, GLsizei height, 630 GLenum format, GLenum type, 631 const struct gl_pixelstore_attrib *packing, 632 GLvoid *pixels) 633{ 634 struct gl_pixelstore_attrib clippedPacking = *packing; 635 636 if (ctx->NewState) 637 _mesa_update_state(ctx); 638 639 /* Do all needed clipping here, so that we can forget about it later */ 640 if (_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) { 641 642 pixels = _mesa_map_pbo_dest(ctx, &clippedPacking, pixels); 643 644 if (pixels) { 645 switch (format) { 646 case GL_STENCIL_INDEX: 647 read_stencil_pixels(ctx, x, y, width, height, type, pixels, 648 &clippedPacking); 649 break; 650 case GL_DEPTH_COMPONENT: 651 read_depth_pixels(ctx, x, y, width, height, type, pixels, 652 &clippedPacking); 653 break; 654 case GL_DEPTH_STENCIL_EXT: 655 read_depth_stencil_pixels(ctx, x, y, width, height, type, pixels, 656 &clippedPacking); 657 break; 658 default: 659 /* all other formats should be color formats */ 660 read_rgba_pixels(ctx, x, y, width, height, format, type, pixels, 661 &clippedPacking); 662 } 663 664 _mesa_unmap_pbo_dest(ctx, &clippedPacking); 665 } 666 } 667} 668 669 670void GLAPIENTRY 671_mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height, 672 GLenum format, GLenum type, GLsizei bufSize, 673 GLvoid *pixels ) 674{ 675 GLenum err; 676 677 GET_CURRENT_CONTEXT(ctx); 678 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 679 680 FLUSH_CURRENT(ctx, 0); 681 682 if (MESA_VERBOSE & VERBOSE_API) 683 _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n", 684 width, height, 685 _mesa_lookup_enum_by_nr(format), 686 _mesa_lookup_enum_by_nr(type), 687 pixels); 688 689 if (width < 0 || height < 0) { 690 _mesa_error( ctx, GL_INVALID_VALUE, 691 "glReadPixels(width=%d height=%d)", width, height ); 692 return; 693 } 694 695 if (ctx->NewState) 696 _mesa_update_state(ctx); 697 698 err = _mesa_error_check_format_and_type(ctx, format, type); 699 if (err != GL_NO_ERROR) { 700 _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)", 701 _mesa_lookup_enum_by_nr(format), 702 _mesa_lookup_enum_by_nr(type)); 703 return; 704 } 705 706 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 707 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 708 "glReadPixels(incomplete framebuffer)" ); 709 return; 710 } 711 712 /* Check that the destination format and source buffer are both 713 * integer-valued or both non-integer-valued. 714 */ 715 if (ctx->Extensions.EXT_texture_integer && _mesa_is_color_format(format)) { 716 const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; 717 const GLboolean srcInteger = _mesa_is_format_integer_color(rb->Format); 718 const GLboolean dstInteger = _mesa_is_enum_format_integer(format); 719 if (dstInteger != srcInteger) { 720 _mesa_error(ctx, GL_INVALID_OPERATION, 721 "glReadPixels(integer / non-integer format mismatch"); 722 return; 723 } 724 } 725 726 if (_mesa_is_user_fbo(ctx->ReadBuffer) && 727 ctx->ReadBuffer->Visual.samples > 0) { 728 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(multisample FBO)"); 729 return; 730 } 731 732 if (!_mesa_source_buffer_exists(ctx, format)) { 733 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)"); 734 return; 735 } 736 737 if (width == 0 || height == 0) 738 return; /* nothing to do */ 739 740 if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1, 741 format, type, bufSize, pixels)) { 742 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 743 _mesa_error(ctx, GL_INVALID_OPERATION, 744 "glReadPixels(out of bounds PBO access)"); 745 } else { 746 _mesa_error(ctx, GL_INVALID_OPERATION, 747 "glReadnPixelsARB(out of bounds access:" 748 " bufSize (%d) is too small)", bufSize); 749 } 750 return; 751 } 752 753 if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && 754 _mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { 755 /* buffer is mapped - that's an error */ 756 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)"); 757 return; 758 } 759 760 ctx->Driver.ReadPixels(ctx, x, y, width, height, 761 format, type, &ctx->Pack, pixels); 762} 763 764void GLAPIENTRY 765_mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, 766 GLenum format, GLenum type, GLvoid *pixels ) 767{ 768 _mesa_ReadnPixelsARB(x, y, width, height, format, type, INT_MAX, pixels); 769} 770