s_copypix.c revision 9dca42a4a10acbf1980c0f2eafb3e28e11ca1bf3
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5.3 4 * 5 * Copyright (C) 1999-2007 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 26#include "glheader.h" 27#include "context.h" 28#include "colormac.h" 29#include "convolve.h" 30#include "histogram.h" 31#include "image.h" 32#include "macros.h" 33#include "imports.h" 34#include "pixel.h" 35 36#include "s_context.h" 37#include "s_depth.h" 38#include "s_span.h" 39#include "s_stencil.h" 40#include "s_zoom.h" 41 42 43 44/** 45 * Determine if there's overlap in an image copy. 46 * This test also compensates for the fact that copies are done from 47 * bottom to top and overlaps can sometimes be handled correctly 48 * without making a temporary image copy. 49 * \return GL_TRUE if the regions overlap, GL_FALSE otherwise. 50 */ 51static GLboolean 52regions_overlap(GLint srcx, GLint srcy, 53 GLint dstx, GLint dsty, 54 GLint width, GLint height, 55 GLfloat zoomX, GLfloat zoomY) 56{ 57 if (zoomX == 1.0 && zoomY == 1.0) { 58 /* no zoom */ 59 if (srcx >= dstx + width || (srcx + width <= dstx)) { 60 return GL_FALSE; 61 } 62 else if (srcy < dsty) { /* this is OK */ 63 return GL_FALSE; 64 } 65 else if (srcy > dsty + height) { 66 return GL_FALSE; 67 } 68 else { 69 return GL_TRUE; 70 } 71 } 72 else { 73 /* add one pixel of slop when zooming, just to be safe */ 74 if ((srcx > dstx + (width * zoomX) + 1) || (srcx + width + 1 < dstx)) { 75 return GL_FALSE; 76 } 77 else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) { 78 return GL_FALSE; 79 } 80 else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) { 81 return GL_FALSE; 82 } 83 else { 84 return GL_TRUE; 85 } 86 } 87} 88 89 90/** 91 * RGBA copypixels with convolution. 92 */ 93static void 94copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy, 95 GLint width, GLint height, GLint destx, GLint desty) 96{ 97 GLint row; 98 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 99 const GLbitfield transferOps = ctx->_ImageTransferState; 100 const GLboolean sink = (ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) 101 || (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink); 102 GLfloat *dest, *tmpImage, *convImage; 103 SWspan span; 104 105 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); 106 _swrast_span_default_attribs(ctx, &span); 107 108 /* allocate space for GLfloat image */ 109 tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat)); 110 if (!tmpImage) { 111 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); 112 return; 113 } 114 convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat)); 115 if (!convImage) { 116 _mesa_free(tmpImage); 117 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); 118 return; 119 } 120 121 /* read source image as float/RGBA */ 122 dest = tmpImage; 123 for (row = 0; row < height; row++) { 124 _swrast_read_rgba_span(ctx, ctx->ReadBuffer->_ColorReadBuffer, 125 width, srcx, srcy + row, GL_FLOAT, dest); 126 dest += 4 * width; 127 } 128 129 /* do the image transfer ops which preceed convolution */ 130 for (row = 0; row < height; row++) { 131 GLfloat (*rgba)[4] = (GLfloat (*)[4]) (tmpImage + row * width * 4); 132 _mesa_apply_rgba_transfer_ops(ctx, 133 transferOps & IMAGE_PRE_CONVOLUTION_BITS, 134 width, rgba); 135 } 136 137 /* do convolution */ 138 if (ctx->Pixel.Convolution2DEnabled) { 139 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage); 140 } 141 else { 142 ASSERT(ctx->Pixel.Separable2DEnabled); 143 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage); 144 } 145 _mesa_free(tmpImage); 146 147 /* do remaining post-convolution image transfer ops */ 148 for (row = 0; row < height; row++) { 149 GLfloat (*rgba)[4] = (GLfloat (*)[4]) (convImage + row * width * 4); 150 _mesa_apply_rgba_transfer_ops(ctx, 151 transferOps & IMAGE_POST_CONVOLUTION_BITS, 152 width, rgba); 153 } 154 155 if (!sink) { 156 /* write the new image */ 157 for (row = 0; row < height; row++) { 158 const GLfloat *src = convImage + row * width * 4; 159 GLfloat *rgba = (GLfloat *) span.array->attribs[FRAG_ATTRIB_COL0]; 160 161 /* copy convolved colors into span array */ 162 _mesa_memcpy(rgba, src, width * 4 * sizeof(GLfloat)); 163 164 /* write span */ 165 span.x = destx; 166 span.y = desty + row; 167 span.end = width; 168 span.array->ChanType = GL_FLOAT; 169 if (zoom) { 170 _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba); 171 } 172 else { 173 _swrast_write_rgba_span(ctx, &span); 174 } 175 } 176 /* restore this */ 177 span.array->ChanType = CHAN_TYPE; 178 } 179 180 _mesa_free(convImage); 181} 182 183 184/** 185 * RGBA copypixels 186 */ 187static void 188copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy, 189 GLint width, GLint height, GLint destx, GLint desty) 190{ 191 GLfloat *tmpImage, *p; 192 GLint sy, dy, stepy, row; 193 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 194 GLint overlapping; 195 GLuint transferOps = ctx->_ImageTransferState; 196 SWspan span; 197 198 if (!ctx->ReadBuffer->_ColorReadBuffer) { 199 /* no readbuffer - OK */ 200 return; 201 } 202 203 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) { 204 copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty); 205 return; 206 } 207 else if (ctx->Pixel.Convolution1DEnabled) { 208 /* make sure we don't apply 1D convolution */ 209 transferOps &= ~(IMAGE_CONVOLUTION_BIT | 210 IMAGE_POST_CONVOLUTION_SCALE_BIAS); 211 } 212 213 if (ctx->DrawBuffer == ctx->ReadBuffer) { 214 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 215 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 216 } 217 else { 218 overlapping = GL_FALSE; 219 } 220 221 /* Determine if copy should be done bottom-to-top or top-to-bottom */ 222 if (!overlapping && srcy < desty) { 223 /* top-down max-to-min */ 224 sy = srcy + height - 1; 225 dy = desty + height - 1; 226 stepy = -1; 227 } 228 else { 229 /* bottom-up min-to-max */ 230 sy = srcy; 231 dy = desty; 232 stepy = 1; 233 } 234 235 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); 236 _swrast_span_default_attribs(ctx, &span); 237 span.arrayAttribs = FRAG_BIT_COL0; /* we'll fill in COL0 attrib values */ 238 239 if (overlapping) { 240 tmpImage = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat) * 4); 241 if (!tmpImage) { 242 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 243 return; 244 } 245 /* read the source image as RGBA/float */ 246 p = tmpImage; 247 for (row = 0; row < height; row++) { 248 _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, 249 width, srcx, sy + row, GL_FLOAT, p ); 250 p += width * 4; 251 } 252 p = tmpImage; 253 } 254 else { 255 tmpImage = NULL; /* silence compiler warnings */ 256 p = NULL; 257 } 258 259 ASSERT(width < MAX_WIDTH); 260 261 for (row = 0; row < height; row++, sy += stepy, dy += stepy) { 262 GLvoid *rgba = span.array->attribs[FRAG_ATTRIB_COL0]; 263 264 /* Get row/span of source pixels */ 265 if (overlapping) { 266 /* get from buffered image */ 267 _mesa_memcpy(rgba, p, width * sizeof(GLfloat) * 4); 268 p += width * 4; 269 } 270 else { 271 /* get from framebuffer */ 272 _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, 273 width, srcx, sy, GL_FLOAT, rgba ); 274 } 275 276 if (transferOps) { 277 _mesa_apply_rgba_transfer_ops(ctx, transferOps, width, 278 (GLfloat (*)[4]) rgba); 279 } 280 281 /* Write color span */ 282 span.x = destx; 283 span.y = dy; 284 span.end = width; 285 span.array->ChanType = GL_FLOAT; 286 if (zoom) { 287 _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba); 288 } 289 else { 290 _swrast_write_rgba_span(ctx, &span); 291 } 292 } 293 294 span.array->ChanType = CHAN_TYPE; /* restore */ 295 296 if (overlapping) 297 _mesa_free(tmpImage); 298} 299 300 301static void 302copy_ci_pixels( GLcontext *ctx, GLint srcx, GLint srcy, 303 GLint width, GLint height, 304 GLint destx, GLint desty ) 305{ 306 GLuint *tmpImage,*p; 307 GLint sy, dy, stepy; 308 GLint j; 309 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 310 GLint overlapping; 311 SWspan span; 312 313 if (!ctx->ReadBuffer->_ColorReadBuffer) { 314 /* no readbuffer - OK */ 315 return; 316 } 317 318 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_INDEX); 319 _swrast_span_default_attribs(ctx, &span); 320 321 if (ctx->DrawBuffer == ctx->ReadBuffer) { 322 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 323 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 324 } 325 else { 326 overlapping = GL_FALSE; 327 } 328 329 /* Determine if copy should be bottom-to-top or top-to-bottom */ 330 if (!overlapping && srcy < desty) { 331 /* top-down max-to-min */ 332 sy = srcy + height - 1; 333 dy = desty + height - 1; 334 stepy = -1; 335 } 336 else { 337 /* bottom-up min-to-max */ 338 sy = srcy; 339 dy = desty; 340 stepy = 1; 341 } 342 343 if (overlapping) { 344 GLint ssy = sy; 345 tmpImage = (GLuint *) _mesa_malloc(width * height * sizeof(GLuint)); 346 if (!tmpImage) { 347 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 348 return; 349 } 350 /* read the image */ 351 p = tmpImage; 352 for (j = 0; j < height; j++, ssy += stepy) { 353 _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, 354 width, srcx, ssy, p ); 355 p += width; 356 } 357 p = tmpImage; 358 } 359 else { 360 tmpImage = NULL; /* silence compiler warning */ 361 p = NULL; 362 } 363 364 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 365 /* Get color indexes */ 366 if (overlapping) { 367 _mesa_memcpy(span.array->index, p, width * sizeof(GLuint)); 368 p += width; 369 } 370 else { 371 _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, 372 width, srcx, sy, span.array->index ); 373 } 374 375 if (ctx->_ImageTransferState) 376 _mesa_apply_ci_transfer_ops(ctx, ctx->_ImageTransferState, 377 width, span.array->index); 378 379 /* write color indexes */ 380 span.x = destx; 381 span.y = dy; 382 span.end = width; 383 if (zoom) 384 _swrast_write_zoomed_index_span(ctx, destx, desty, &span); 385 else 386 _swrast_write_index_span(ctx, &span); 387 } 388 389 if (overlapping) 390 _mesa_free(tmpImage); 391} 392 393 394/** 395 * Convert floating point Z values to integer Z values with pixel transfer's 396 * Z scale and bias. 397 */ 398static void 399scale_and_bias_z(GLcontext *ctx, GLuint width, 400 const GLfloat depth[], GLuint z[]) 401{ 402 const GLuint depthMax = ctx->DrawBuffer->_DepthMax; 403 GLuint i; 404 405 if (depthMax <= 0xffffff && 406 ctx->Pixel.DepthScale == 1.0 && 407 ctx->Pixel.DepthBias == 0.0) { 408 /* no scale or bias and no clamping and no worry of overflow */ 409 const GLfloat depthMaxF = ctx->DrawBuffer->_DepthMaxF; 410 for (i = 0; i < width; i++) { 411 z[i] = (GLuint) (depth[i] * depthMaxF); 412 } 413 } 414 else { 415 /* need to be careful with overflow */ 416 const GLdouble depthMaxF = ctx->DrawBuffer->_DepthMaxF; 417 for (i = 0; i < width; i++) { 418 GLdouble d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias; 419 d = CLAMP(d, 0.0, 1.0) * depthMaxF; 420 if (d >= depthMaxF) 421 z[i] = depthMax; 422 else 423 z[i] = (GLuint) d; 424 } 425 } 426} 427 428 429 430/* 431 * TODO: Optimize!!!! 432 */ 433static void 434copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy, 435 GLint width, GLint height, 436 GLint destx, GLint desty ) 437{ 438 struct gl_framebuffer *fb = ctx->ReadBuffer; 439 struct gl_renderbuffer *readRb = fb->_DepthBuffer; 440 GLfloat *p, *tmpImage; 441 GLint sy, dy, stepy; 442 GLint j; 443 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 444 GLint overlapping; 445 SWspan span; 446 447 if (!readRb) { 448 /* no readbuffer - OK */ 449 return; 450 } 451 452 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z); 453 _swrast_span_default_attribs(ctx, &span); 454 455 if (ctx->DrawBuffer == ctx->ReadBuffer) { 456 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 457 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 458 } 459 else { 460 overlapping = GL_FALSE; 461 } 462 463 /* Determine if copy should be bottom-to-top or top-to-bottom */ 464 if (!overlapping && srcy < desty) { 465 /* top-down max-to-min */ 466 sy = srcy + height - 1; 467 dy = desty + height - 1; 468 stepy = -1; 469 } 470 else { 471 /* bottom-up min-to-max */ 472 sy = srcy; 473 dy = desty; 474 stepy = 1; 475 } 476 477 if (overlapping) { 478 GLint ssy = sy; 479 tmpImage = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat)); 480 if (!tmpImage) { 481 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 482 return; 483 } 484 p = tmpImage; 485 for (j = 0; j < height; j++, ssy += stepy) { 486 _swrast_read_depth_span_float(ctx, readRb, width, srcx, ssy, p); 487 p += width; 488 } 489 p = tmpImage; 490 } 491 else { 492 tmpImage = NULL; /* silence compiler warning */ 493 p = NULL; 494 } 495 496 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 497 GLfloat depth[MAX_WIDTH]; 498 /* get depth values */ 499 if (overlapping) { 500 _mesa_memcpy(depth, p, width * sizeof(GLfloat)); 501 p += width; 502 } 503 else { 504 _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth); 505 } 506 507 /* apply scale and bias */ 508 scale_and_bias_z(ctx, width, depth, span.array->z); 509 510 /* write depth values */ 511 span.x = destx; 512 span.y = dy; 513 span.end = width; 514 if (fb->Visual.rgbMode) { 515 if (zoom) 516 _swrast_write_zoomed_depth_span(ctx, destx, desty, &span); 517 else 518 _swrast_write_rgba_span(ctx, &span); 519 } 520 else { 521 if (zoom) 522 _swrast_write_zoomed_depth_span(ctx, destx, desty, &span); 523 else 524 _swrast_write_index_span(ctx, &span); 525 } 526 } 527 528 if (overlapping) 529 _mesa_free(tmpImage); 530} 531 532 533 534static void 535copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy, 536 GLint width, GLint height, 537 GLint destx, GLint desty ) 538{ 539 struct gl_framebuffer *fb = ctx->ReadBuffer; 540 struct gl_renderbuffer *rb = fb->_StencilBuffer; 541 GLint sy, dy, stepy; 542 GLint j; 543 GLstencil *p, *tmpImage; 544 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 545 GLint overlapping; 546 547 if (!rb) { 548 /* no readbuffer - OK */ 549 return; 550 } 551 552 if (ctx->DrawBuffer == ctx->ReadBuffer) { 553 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 554 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 555 } 556 else { 557 overlapping = GL_FALSE; 558 } 559 560 /* Determine if copy should be bottom-to-top or top-to-bottom */ 561 if (!overlapping && srcy < desty) { 562 /* top-down max-to-min */ 563 sy = srcy + height - 1; 564 dy = desty + height - 1; 565 stepy = -1; 566 } 567 else { 568 /* bottom-up min-to-max */ 569 sy = srcy; 570 dy = desty; 571 stepy = 1; 572 } 573 574 if (overlapping) { 575 GLint ssy = sy; 576 tmpImage = (GLstencil *) _mesa_malloc(width * height * sizeof(GLstencil)); 577 if (!tmpImage) { 578 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 579 return; 580 } 581 p = tmpImage; 582 for (j = 0; j < height; j++, ssy += stepy) { 583 _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p ); 584 p += width; 585 } 586 p = tmpImage; 587 } 588 else { 589 tmpImage = NULL; /* silence compiler warning */ 590 p = NULL; 591 } 592 593 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 594 GLstencil stencil[MAX_WIDTH]; 595 596 /* Get stencil values */ 597 if (overlapping) { 598 _mesa_memcpy(stencil, p, width * sizeof(GLstencil)); 599 p += width; 600 } 601 else { 602 _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil ); 603 } 604 605 _mesa_apply_stencil_transfer_ops(ctx, width, stencil); 606 607 /* Write stencil values */ 608 if (zoom) { 609 _swrast_write_zoomed_stencil_span(ctx, destx, desty, width, 610 destx, dy, stencil); 611 } 612 else { 613 _swrast_write_stencil_span( ctx, width, destx, dy, stencil ); 614 } 615 } 616 617 if (overlapping) 618 _mesa_free(tmpImage); 619} 620 621 622/** 623 * This isn't terribly efficient. If a driver really has combined 624 * depth/stencil buffers the driver should implement an optimized 625 * CopyPixels function. 626 */ 627static void 628copy_depth_stencil_pixels(GLcontext *ctx, 629 const GLint srcX, const GLint srcY, 630 const GLint width, const GLint height, 631 const GLint destX, const GLint destY) 632{ 633 struct gl_renderbuffer *stencilReadRb, *depthReadRb, *depthDrawRb; 634 GLint sy, dy, stepy; 635 GLint j; 636 GLstencil *tempStencilImage = NULL, *stencilPtr = NULL; 637 GLfloat *tempDepthImage = NULL, *depthPtr = NULL; 638 const GLfloat depthScale = ctx->DrawBuffer->_DepthMaxF; 639 const GLuint stencilMask = ctx->Stencil.WriteMask[0]; 640 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 641 const GLboolean scaleOrBias 642 = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; 643 GLint overlapping; 644 645 depthDrawRb = ctx->DrawBuffer->_DepthBuffer; 646 depthReadRb = ctx->ReadBuffer->_DepthBuffer; 647 stencilReadRb = ctx->ReadBuffer->_StencilBuffer; 648 649 ASSERT(depthDrawRb); 650 ASSERT(depthReadRb); 651 ASSERT(stencilReadRb); 652 653 if (ctx->DrawBuffer == ctx->ReadBuffer) { 654 overlapping = regions_overlap(srcX, srcY, destX, destY, width, height, 655 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 656 } 657 else { 658 overlapping = GL_FALSE; 659 } 660 661 /* Determine if copy should be bottom-to-top or top-to-bottom */ 662 if (!overlapping && srcY < destY) { 663 /* top-down max-to-min */ 664 sy = srcY + height - 1; 665 dy = destY + height - 1; 666 stepy = -1; 667 } 668 else { 669 /* bottom-up min-to-max */ 670 sy = srcY; 671 dy = destY; 672 stepy = 1; 673 } 674 675 if (overlapping) { 676 GLint ssy = sy; 677 678 if (stencilMask != 0x0) { 679 tempStencilImage 680 = (GLstencil *) _mesa_malloc(width * height * sizeof(GLstencil)); 681 if (!tempStencilImage) { 682 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); 683 return; 684 } 685 686 /* get copy of stencil pixels */ 687 stencilPtr = tempStencilImage; 688 for (j = 0; j < height; j++, ssy += stepy) { 689 _swrast_read_stencil_span(ctx, stencilReadRb, 690 width, srcX, ssy, stencilPtr); 691 stencilPtr += width; 692 } 693 stencilPtr = tempStencilImage; 694 } 695 696 if (ctx->Depth.Mask) { 697 tempDepthImage 698 = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat)); 699 if (!tempDepthImage) { 700 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); 701 _mesa_free(tempStencilImage); 702 return; 703 } 704 705 /* get copy of depth pixels */ 706 depthPtr = tempDepthImage; 707 for (j = 0; j < height; j++, ssy += stepy) { 708 _swrast_read_depth_span_float(ctx, depthReadRb, 709 width, srcX, ssy, depthPtr); 710 depthPtr += width; 711 } 712 depthPtr = tempDepthImage; 713 } 714 } 715 716 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 717 if (stencilMask != 0x0) { 718 GLstencil stencil[MAX_WIDTH]; 719 720 /* Get stencil values */ 721 if (overlapping) { 722 _mesa_memcpy(stencil, stencilPtr, width * sizeof(GLstencil)); 723 stencilPtr += width; 724 } 725 else { 726 _swrast_read_stencil_span(ctx, stencilReadRb, 727 width, srcX, sy, stencil); 728 } 729 730 _mesa_apply_stencil_transfer_ops(ctx, width, stencil); 731 732 /* Write values */ 733 if (zoom) { 734 _swrast_write_zoomed_stencil_span(ctx, destX, destY, width, 735 destX, dy, stencil); 736 } 737 else { 738 _swrast_write_stencil_span( ctx, width, destX, dy, stencil ); 739 } 740 } 741 742 if (ctx->Depth.Mask) { 743 GLfloat depth[MAX_WIDTH]; 744 GLuint zVals32[MAX_WIDTH]; 745 GLushort zVals16[MAX_WIDTH]; 746 GLvoid *zVals; 747 GLuint zBytes; 748 749 /* get depth values */ 750 if (overlapping) { 751 _mesa_memcpy(depth, depthPtr, width * sizeof(GLfloat)); 752 depthPtr += width; 753 } 754 else { 755 _swrast_read_depth_span_float(ctx, depthReadRb, 756 width, srcX, sy, depth); 757 } 758 759 /* scale & bias */ 760 if (scaleOrBias) { 761 _mesa_scale_and_bias_depth(ctx, width, depth); 762 } 763 /* convert to integer Z values */ 764 if (depthDrawRb->DataType == GL_UNSIGNED_SHORT) { 765 GLint k; 766 for (k = 0; k < width; k++) 767 zVals16[k] = (GLushort) (depth[k] * depthScale); 768 zVals = zVals16; 769 zBytes = 2; 770 } 771 else { 772 GLint k; 773 for (k = 0; k < width; k++) 774 zVals32[k] = (GLuint) (depth[k] * depthScale); 775 zVals = zVals32; 776 zBytes = 4; 777 } 778 779 /* Write values */ 780 if (zoom) { 781 _swrast_write_zoomed_z_span(ctx, destX, destY, width, 782 destX, dy, zVals); 783 } 784 else { 785 _swrast_put_row(ctx, depthDrawRb, width, destX, dy, zVals, zBytes); 786 } 787 } 788 } 789 790 if (tempStencilImage) 791 _mesa_free(tempStencilImage); 792 793 if (tempDepthImage) 794 _mesa_free(tempDepthImage); 795} 796 797 798 799/** 800 * Try to do a fast copy pixels. 801 */ 802static GLboolean 803fast_copy_pixels(GLcontext *ctx, 804 GLint srcX, GLint srcY, GLsizei width, GLsizei height, 805 GLint dstX, GLint dstY, GLenum type) 806{ 807 struct gl_framebuffer *srcFb = ctx->ReadBuffer; 808 struct gl_framebuffer *dstFb = ctx->DrawBuffer; 809 struct gl_renderbuffer *srcRb, *dstRb; 810 GLint row, yStep; 811 812 if (SWRAST_CONTEXT(ctx)->_RasterMask != 0x0 || 813 ctx->Pixel.ZoomX != 1.0F || 814 ctx->Pixel.ZoomY != 1.0F || 815 ctx->_ImageTransferState) { 816 /* can't handle these */ 817 return GL_FALSE; 818 } 819 820 if (type == GL_COLOR) { 821 if (dstFb->_NumColorDrawBuffers[0] != 1) 822 return GL_FALSE; 823 srcRb = srcFb->_ColorReadBuffer; 824 dstRb = dstFb->_ColorDrawBuffers[0][0]; 825 } 826 else if (type == GL_STENCIL) { 827 srcRb = srcFb->_StencilBuffer; 828 dstRb = dstFb->_StencilBuffer; 829 } 830 else if (type == GL_DEPTH) { 831 srcRb = srcFb->_DepthBuffer; 832 dstRb = dstFb->_DepthBuffer; 833 } 834 else { 835 ASSERT(type == GL_DEPTH_STENCIL_EXT); 836 /* XXX correct? */ 837 srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer; 838 dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer; 839 } 840 841 /* src and dst renderbuffers must be same format and type */ 842 if (!srcRb || !dstRb || 843 srcRb->DataType != dstRb->DataType || 844 srcRb->_BaseFormat != dstRb->_BaseFormat) { 845 return GL_FALSE; 846 } 847 848 /* clipping not supported */ 849 if (srcX < 0 || srcX + width > (GLint) srcFb->Width || 850 srcY < 0 || srcY + height > (GLint) srcFb->Height || 851 dstX < dstFb->_Xmin || dstX + width > dstFb->_Xmax || 852 dstY < dstFb->_Ymin || dstY + height > dstFb->_Ymax) { 853 return GL_FALSE; 854 } 855 856 /* overlapping src/dst doesn't matter, just determine Y direction */ 857 if (srcY < dstY) { 858 /* top-down max-to-min */ 859 srcY = srcY + height - 1; 860 dstY = dstY + height - 1; 861 yStep = -1; 862 } 863 else { 864 /* bottom-up min-to-max */ 865 yStep = 1; 866 } 867 868 for (row = 0; row < height; row++) { 869 GLuint temp[MAX_WIDTH][4]; 870 srcRb->GetRow(ctx, srcRb, width, srcX, srcY, temp); 871 dstRb->PutRow(ctx, dstRb, width, dstX, dstY, temp, NULL); 872 srcY += yStep; 873 dstY += yStep; 874 } 875 876 return GL_TRUE; 877} 878 879 880/** 881 * Do software-based glCopyPixels. 882 * By time we get here, all parameters will have been error-checked. 883 */ 884void 885_swrast_CopyPixels( GLcontext *ctx, 886 GLint srcx, GLint srcy, GLsizei width, GLsizei height, 887 GLint destx, GLint desty, GLenum type ) 888{ 889 SWcontext *swrast = SWRAST_CONTEXT(ctx); 890 RENDER_START(swrast,ctx); 891 892 if (swrast->NewState) 893 _swrast_validate_derived( ctx ); 894 895 if (!fast_copy_pixels(ctx, srcx, srcy, width, height, destx, desty, type)) { 896 switch (type) { 897 case GL_COLOR: 898 if (ctx->Visual.rgbMode) { 899 copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty ); 900 } 901 else { 902 copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty ); 903 } 904 break; 905 case GL_DEPTH: 906 copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty ); 907 break; 908 case GL_STENCIL: 909 copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty ); 910 break; 911 case GL_DEPTH_STENCIL_EXT: 912 copy_depth_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty); 913 break; 914 default: 915 _mesa_problem(ctx, "unexpected type in _swrast_CopyPixels"); 916 } 917 } 918 919 RENDER_FINISH(swrast,ctx); 920} 921