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