s_copypix.c revision f9995b30756140724f41daf963fa06167912be7f
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(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 */
207static void
208scale_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 */
242static void
243copy_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
336static void
337copy_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 */
429static void
430copy_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 */
604static GLboolean
605fast_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 */
686void
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}
721