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