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