Drop GLcontext typedef and use struct gl_context instead
[mesa.git] / src / mesa / swrast / s_copypix.c
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 */
49 static GLboolean
50 regions_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 */
98 static void
99 copy_rgba_pixels(struct gl_context *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 */
207 static void
208 scale_and_bias_z(struct gl_context *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 */
242 static void
243 copy_depth_pixels( struct gl_context *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
336 static void
337 copy_stencil_pixels( struct gl_context *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 */
429 static void
430 copy_depth_stencil_pixels(struct gl_context *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 */
604 static GLboolean
605 fast_copy_pixels(struct gl_context *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 */
686 void
687 _swrast_CopyPixels( struct gl_context *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 }