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