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