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