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