s_copypix.c revision 38a1c2b4959d35236933c14d3944cce94283ca30
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5.2 4 * 5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26#include "glheader.h" 27#include "context.h" 28#include "colormac.h" 29#include "convolve.h" 30#include "histogram.h" 31#include "image.h" 32#include "macros.h" 33#include "imports.h" 34#include "pixel.h" 35 36#include "s_context.h" 37#include "s_depth.h" 38#include "s_span.h" 39#include "s_stencil.h" 40#include "s_zoom.h" 41 42 43 44/** 45 * Determine if there's overlap in an image copy. 46 * This test also compensates for the fact that copies are done from 47 * bottom to top and overlaps can sometimes be handled correctly 48 * without making a temporary image copy. 49 * \return GL_TRUE if the regions overlap, GL_FALSE otherwise. 50 */ 51static GLboolean 52regions_overlap(GLint srcx, GLint srcy, 53 GLint dstx, GLint dsty, 54 GLint width, GLint height, 55 GLfloat zoomX, GLfloat zoomY) 56{ 57 if (zoomX == 1.0 && zoomY == 1.0) { 58 /* no zoom */ 59 if (srcx >= dstx + width || (srcx + width <= dstx)) { 60 return GL_FALSE; 61 } 62 else if (srcy < dsty) { /* this is OK */ 63 return GL_FALSE; 64 } 65 else if (srcy > dsty + height) { 66 return GL_FALSE; 67 } 68 else { 69 return GL_TRUE; 70 } 71 } 72 else { 73 /* add one pixel of slop when zooming, just to be safe */ 74 if ((srcx > dstx + (width * zoomX) + 1) || (srcx + width + 1 < dstx)) { 75 return GL_FALSE; 76 } 77 else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) { 78 return GL_FALSE; 79 } 80 else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) { 81 return GL_FALSE; 82 } 83 else { 84 return GL_TRUE; 85 } 86 } 87} 88 89 90/** 91 * RGBA copypixels with convolution. 92 */ 93static void 94copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy, 95 GLint width, GLint height, GLint destx, GLint desty) 96{ 97 SWcontext *swrast = SWRAST_CONTEXT(ctx); 98 GLint row; 99 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 100 const GLbitfield transferOps = ctx->_ImageTransferState; 101 const GLboolean sink = (ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) 102 || (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink); 103 GLfloat *dest, *tmpImage, *convImage; 104 SWspan span; 105 106 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); 107 108 if (ctx->Depth.Test) 109 _swrast_span_default_z(ctx, &span); 110 if (swrast->_FogEnabled) 111 _swrast_span_default_fog(ctx, &span); 112 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 = span.array->color.sz1.rgba; /* row storage */ 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 /* Determine if copy should be done bottom-to-top or top-to-bottom */ 222 if (srcy < desty) { 223 /* top-down max-to-min */ 224 sy = srcy + height - 1; 225 dy = desty + height - 1; 226 stepy = -1; 227 } 228 else { 229 /* bottom-up min-to-max */ 230 sy = srcy; 231 dy = desty; 232 stepy = 1; 233 } 234 235 if (ctx->DrawBuffer == ctx->ReadBuffer) { 236 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 237 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 238 } 239 else { 240 overlapping = GL_FALSE; 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 /* Determine if copy should be bottom-to-top or top-to-bottom */ 334 if (srcy<desty) { 335 /* top-down max-to-min */ 336 sy = srcy + height - 1; 337 dy = desty + height - 1; 338 stepy = -1; 339 } 340 else { 341 /* bottom-up min-to-max */ 342 sy = srcy; 343 dy = desty; 344 stepy = 1; 345 } 346 347 if (ctx->DrawBuffer == ctx->ReadBuffer) { 348 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 349 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 350 } 351 else { 352 overlapping = GL_FALSE; 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 /* Determine if copy should be bottom-to-top or top-to-bottom */ 473 if (srcy<desty) { 474 /* top-down max-to-min */ 475 sy = srcy + height - 1; 476 dy = desty + height - 1; 477 stepy = -1; 478 } 479 else { 480 /* bottom-up min-to-max */ 481 sy = srcy; 482 dy = desty; 483 stepy = 1; 484 } 485 486 if (ctx->DrawBuffer == ctx->ReadBuffer) { 487 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 488 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 489 } 490 else { 491 overlapping = GL_FALSE; 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_rgba_span(ctx, destx, desty, &span, 540 span.array->rgba); 541 else 542 _swrast_write_rgba_span(ctx, &span); 543 } 544 else { 545 if (zoom) 546 _swrast_write_zoomed_index_span(ctx, destx, desty, &span); 547 else 548 _swrast_write_index_span(ctx, &span); 549 } 550 } 551 552 if (overlapping) 553 _mesa_free(tmpImage); 554} 555 556 557 558static void 559copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy, 560 GLint width, GLint height, 561 GLint destx, GLint desty ) 562{ 563 struct gl_framebuffer *fb = ctx->ReadBuffer; 564 struct gl_renderbuffer *rb = fb->_StencilBuffer; 565 GLint sy, dy, stepy; 566 GLint j; 567 GLstencil *p, *tmpImage; 568 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 569 GLint overlapping; 570 571 if (!rb) { 572 /* no readbuffer - OK */ 573 return; 574 } 575 576 /* Determine if copy should be bottom-to-top or top-to-bottom */ 577 if (srcy < desty) { 578 /* top-down max-to-min */ 579 sy = srcy + height - 1; 580 dy = desty + height - 1; 581 stepy = -1; 582 } 583 else { 584 /* bottom-up min-to-max */ 585 sy = srcy; 586 dy = desty; 587 stepy = 1; 588 } 589 590 if (ctx->DrawBuffer == ctx->ReadBuffer) { 591 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 592 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 593 } 594 else { 595 overlapping = GL_FALSE; 596 } 597 598 if (overlapping) { 599 GLint ssy = sy; 600 tmpImage = (GLstencil *) _mesa_malloc(width * height * sizeof(GLstencil)); 601 if (!tmpImage) { 602 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 603 return; 604 } 605 p = tmpImage; 606 for (j = 0; j < height; j++, ssy += stepy) { 607 _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p ); 608 p += width; 609 } 610 p = tmpImage; 611 } 612 else { 613 tmpImage = NULL; /* silence compiler warning */ 614 p = NULL; 615 } 616 617 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 618 GLstencil stencil[MAX_WIDTH]; 619 620 /* Get stencil values */ 621 if (overlapping) { 622 _mesa_memcpy(stencil, p, width * sizeof(GLstencil)); 623 p += width; 624 } 625 else { 626 _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil ); 627 } 628 629 _mesa_apply_stencil_transfer_ops(ctx, width, stencil); 630 631 /* Write stencil values */ 632 if (zoom) { 633 _swrast_write_zoomed_stencil_span(ctx, destx, desty, width, 634 destx, dy, stencil); 635 } 636 else { 637 _swrast_write_stencil_span( ctx, width, destx, dy, stencil ); 638 } 639 } 640 641 if (overlapping) 642 _mesa_free(tmpImage); 643} 644 645 646/** 647 * This isn't terribly efficient. If a driver really has combined 648 * depth/stencil buffers the driver should implement an optimized 649 * CopyPixels function. 650 */ 651static void 652copy_depth_stencil_pixels(GLcontext *ctx, 653 const GLint srcX, const GLint srcY, 654 const GLint width, const GLint height, 655 const GLint destX, const GLint destY) 656{ 657 struct gl_renderbuffer *stencilReadRb, *depthReadRb, *depthDrawRb; 658 GLint sy, dy, stepy; 659 GLint j; 660 GLstencil *tempStencilImage = NULL, *stencilPtr = NULL; 661 GLfloat *tempDepthImage = NULL, *depthPtr = NULL; 662 const GLfloat depthScale = ctx->DrawBuffer->_DepthMaxF; 663 const GLuint stencilMask = ctx->Stencil.WriteMask[0]; 664 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 665 const GLboolean scaleOrBias 666 = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; 667 GLint overlapping; 668 669 depthDrawRb = ctx->DrawBuffer->_DepthBuffer; 670 depthReadRb = ctx->ReadBuffer->_DepthBuffer; 671 stencilReadRb = ctx->ReadBuffer->_StencilBuffer; 672 673 ASSERT(depthDrawRb); 674 ASSERT(depthReadRb); 675 ASSERT(stencilReadRb); 676 677 /* Determine if copy should be bottom-to-top or top-to-bottom */ 678 if (srcY < destY) { 679 /* top-down max-to-min */ 680 sy = srcY + height - 1; 681 dy = destY + height - 1; 682 stepy = -1; 683 } 684 else { 685 /* bottom-up min-to-max */ 686 sy = srcY; 687 dy = destY; 688 stepy = 1; 689 } 690 691 if (ctx->DrawBuffer == ctx->ReadBuffer) { 692 overlapping = regions_overlap(srcX, srcY, destX, destY, width, height, 693 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 694 } 695 else { 696 overlapping = GL_FALSE; 697 } 698 699 if (overlapping) { 700 GLint ssy = sy; 701 702 if (stencilMask != 0x0) { 703 tempStencilImage 704 = (GLstencil *) _mesa_malloc(width * height * sizeof(GLstencil)); 705 if (!tempStencilImage) { 706 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); 707 return; 708 } 709 710 /* get copy of stencil pixels */ 711 stencilPtr = tempStencilImage; 712 for (j = 0; j < height; j++, ssy += stepy) { 713 _swrast_read_stencil_span(ctx, stencilReadRb, 714 width, srcX, ssy, stencilPtr); 715 stencilPtr += width; 716 } 717 stencilPtr = tempStencilImage; 718 } 719 720 if (ctx->Depth.Mask) { 721 tempDepthImage 722 = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat)); 723 if (!tempDepthImage) { 724 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); 725 _mesa_free(tempStencilImage); 726 return; 727 } 728 729 /* get copy of depth pixels */ 730 depthPtr = tempDepthImage; 731 for (j = 0; j < height; j++, ssy += stepy) { 732 _swrast_read_depth_span_float(ctx, depthReadRb, 733 width, srcX, ssy, depthPtr); 734 depthPtr += width; 735 } 736 depthPtr = tempDepthImage; 737 } 738 } 739 740 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 741 if (stencilMask != 0x0) { 742 GLstencil stencil[MAX_WIDTH]; 743 744 /* Get stencil values */ 745 if (overlapping) { 746 _mesa_memcpy(stencil, stencilPtr, width * sizeof(GLstencil)); 747 stencilPtr += width; 748 } 749 else { 750 _swrast_read_stencil_span(ctx, stencilReadRb, 751 width, srcX, sy, stencil); 752 } 753 754 _mesa_apply_stencil_transfer_ops(ctx, width, stencil); 755 756 /* Write values */ 757 if (zoom) { 758 _swrast_write_zoomed_stencil_span(ctx, destX, destY, width, 759 destX, dy, stencil); 760 } 761 else { 762 _swrast_write_stencil_span( ctx, width, destX, dy, stencil ); 763 } 764 } 765 766 if (ctx->Depth.Mask) { 767 GLfloat depth[MAX_WIDTH]; 768 GLuint zVals32[MAX_WIDTH]; 769 GLushort zVals16[MAX_WIDTH]; 770 GLvoid *zVals; 771 GLuint zBytes; 772 773 /* get depth values */ 774 if (overlapping) { 775 _mesa_memcpy(depth, depthPtr, width * sizeof(GLfloat)); 776 depthPtr += width; 777 } 778 else { 779 _swrast_read_depth_span_float(ctx, depthReadRb, 780 width, srcX, sy, depth); 781 } 782 783 /* scale & bias */ 784 if (scaleOrBias) { 785 _mesa_scale_and_bias_depth(ctx, width, depth); 786 } 787 /* convert to integer Z values */ 788 if (depthDrawRb->DataType == GL_UNSIGNED_SHORT) { 789 GLint k; 790 for (k = 0; k < width; k++) 791 zVals16[k] = (GLushort) (depth[k] * depthScale); 792 zVals = zVals16; 793 zBytes = 2; 794 } 795 else { 796 GLint k; 797 for (k = 0; k < width; k++) 798 zVals32[k] = (GLuint) (depth[k] * depthScale); 799 zVals = zVals32; 800 zBytes = 4; 801 } 802 803 /* Write values */ 804 if (zoom) { 805 _swrast_write_zoomed_z_span(ctx, destX, destY, width, 806 destX, dy, zVals); 807 } 808 else { 809 _swrast_put_row(ctx, depthDrawRb, width, destX, dy, zVals, zBytes); 810 } 811 } 812 } 813 814 if (tempStencilImage) 815 _mesa_free(tempStencilImage); 816 817 if (tempDepthImage) 818 _mesa_free(tempDepthImage); 819} 820 821 822 823/** 824 * Try to do a fast copy pixels. 825 */ 826static GLboolean 827fast_copy_pixels(GLcontext *ctx, 828 GLint srcX, GLint srcY, GLsizei width, GLsizei height, 829 GLint dstX, GLint dstY, GLenum type) 830{ 831 struct gl_framebuffer *srcFb = ctx->ReadBuffer; 832 struct gl_framebuffer *dstFb = ctx->DrawBuffer; 833 struct gl_renderbuffer *srcRb, *dstRb; 834 GLint row, yStep; 835 836 if (SWRAST_CONTEXT(ctx)->_RasterMask != 0x0 || 837 ctx->Pixel.ZoomX != 1.0F || 838 ctx->Pixel.ZoomY != 1.0F || 839 ctx->_ImageTransferState) { 840 /* can't handle these */ 841 return GL_FALSE; 842 } 843 844 if (type == GL_COLOR) { 845 if (dstFb->_NumColorDrawBuffers[0] != 1) 846 return GL_FALSE; 847 srcRb = srcFb->_ColorReadBuffer; 848 dstRb = dstFb->_ColorDrawBuffers[0][0]; 849 } 850 else if (type == GL_STENCIL) { 851 srcRb = srcFb->_StencilBuffer; 852 dstRb = dstFb->_StencilBuffer; 853 } 854 else if (type == GL_DEPTH) { 855 srcRb = srcFb->_DepthBuffer; 856 dstRb = dstFb->_DepthBuffer; 857 } 858 else { 859 ASSERT(type == GL_DEPTH_STENCIL_EXT); 860 /* XXX correct? */ 861 srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer; 862 dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer; 863 } 864 865 /* src and dst renderbuffers must be same format and type */ 866 if (!srcRb || !dstRb || 867 srcRb->DataType != dstRb->DataType || 868 srcRb->_BaseFormat != dstRb->_BaseFormat) { 869 return GL_FALSE; 870 } 871 872 /* clipping not supported */ 873 if (srcX < 0 || srcX + width > (GLint) srcFb->Width || 874 srcY < 0 || srcY + height > (GLint) srcFb->Height || 875 dstX < dstFb->_Xmin || dstX + width > dstFb->_Xmax || 876 dstY < dstFb->_Ymin || dstY + height > dstFb->_Ymax) { 877 return GL_FALSE; 878 } 879 880 /* overlapping src/dst doesn't matter, just determine Y direction */ 881 if (srcY < dstY) { 882 /* top-down max-to-min */ 883 srcY = srcY + height - 1; 884 dstY = dstY + height - 1; 885 yStep = -1; 886 } 887 else { 888 /* bottom-up min-to-max */ 889 yStep = 1; 890 } 891 892 for (row = 0; row < height; row++) { 893 GLuint temp[MAX_WIDTH][4]; 894 srcRb->GetRow(ctx, srcRb, width, srcX, srcY, temp); 895 dstRb->PutRow(ctx, dstRb, width, dstX, dstY, temp, NULL); 896 srcY += yStep; 897 dstY += yStep; 898 } 899 900 return GL_TRUE; 901} 902 903 904/** 905 * Do software-based glCopyPixels. 906 * By time we get here, all parameters will have been error-checked. 907 */ 908void 909_swrast_CopyPixels( GLcontext *ctx, 910 GLint srcx, GLint srcy, GLsizei width, GLsizei height, 911 GLint destx, GLint desty, GLenum type ) 912{ 913 SWcontext *swrast = SWRAST_CONTEXT(ctx); 914 RENDER_START(swrast,ctx); 915 916 if (swrast->NewState) 917 _swrast_validate_derived( ctx ); 918 919 if (!fast_copy_pixels(ctx, srcx, srcy, width, height, destx, desty, type)) { 920 switch (type) { 921 case GL_COLOR: 922 if (ctx->Visual.rgbMode) { 923 copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty ); 924 } 925 else { 926 copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty ); 927 } 928 break; 929 case GL_DEPTH: 930 copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty ); 931 break; 932 case GL_STENCIL: 933 copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty ); 934 break; 935 case GL_DEPTH_STENCIL_EXT: 936 copy_depth_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty); 937 break; 938 default: 939 _mesa_problem(ctx, "unexpected type in _swrast_CopyPixels"); 940 } 941 } 942 943 RENDER_FINISH(swrast,ctx); 944} 945