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