1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 
26 #include "main/glheader.h"
27 #include "main/context.h"
28 #include "main/condrender.h"
29 #include "main/macros.h"
30 #include "main/blit.h"
31 #include "main/pixeltransfer.h"
32 
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
regions_overlap(GLint srcx,GLint srcy,GLint dstx,GLint dsty,GLint width,GLint height,GLfloat zoomX,GLfloat zoomY)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.0F && zoomY == 1.0F) {
56       return _mesa_regions_overlap(srcx, srcy, srcx + width, srcy + height,
57                                    dstx, dsty, dstx + width, dsty + height);
58    }
59    else {
60       /* add one pixel of slop when zooming, just to be safe */
61       if (srcx > (dstx + ((zoomX > 0.0F) ? (width * zoomX + 1.0F) : 0.0F))) {
62          /* src is completely right of dest */
63          return GL_FALSE;
64       }
65       else if (srcx + width + 1.0F < dstx + ((zoomX > 0.0F) ? 0.0F : (width * zoomX))) {
66          /* src is completely left of dest */
67          return GL_FALSE;
68       }
69       else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) {
70          /* src is completely below dest */
71          return GL_FALSE;
72       }
73       else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) {
74          /* src is completely above dest */
75          return GL_FALSE;
76       }
77       else {
78          return GL_TRUE;
79       }
80    }
81 }
82 
83 
84 /**
85  * RGBA copypixels
86  */
87 static void
copy_rgba_pixels(struct gl_context * ctx,GLint srcx,GLint srcy,GLint width,GLint height,GLint destx,GLint desty)88 copy_rgba_pixels(struct gl_context *ctx, GLint srcx, GLint srcy,
89                  GLint width, GLint height, GLint destx, GLint desty)
90 {
91    GLfloat *tmpImage, *p;
92    GLint sy, dy, stepy, row;
93    const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
94    GLint overlapping;
95    GLuint transferOps = ctx->_ImageTransferState;
96    SWspan span;
97 
98    if (!ctx->ReadBuffer->_ColorReadBuffer) {
99       /* no readbuffer - OK */
100       return;
101    }
102 
103    if (ctx->DrawBuffer == ctx->ReadBuffer) {
104       overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
105                                     ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
106    }
107    else {
108       overlapping = GL_FALSE;
109    }
110 
111    /* Determine if copy should be done bottom-to-top or top-to-bottom */
112    if (!overlapping && srcy < desty) {
113       /* top-down  max-to-min */
114       sy = srcy + height - 1;
115       dy = desty + height - 1;
116       stepy = -1;
117    }
118    else {
119       /* bottom-up  min-to-max */
120       sy = srcy;
121       dy = desty;
122       stepy = 1;
123    }
124 
125    INIT_SPAN(span, GL_BITMAP);
126    _swrast_span_default_attribs(ctx, &span);
127    span.arrayMask = SPAN_RGBA;
128    span.arrayAttribs = VARYING_BIT_COL0; /* we'll fill in COL0 attrib values */
129 
130    if (overlapping) {
131       tmpImage = malloc(width * height * sizeof(GLfloat) * 4);
132       if (!tmpImage) {
133          _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
134          return;
135       }
136       /* read the source image as RGBA/float */
137       p = tmpImage;
138       for (row = 0; row < height; row++) {
139          _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
140                                  width, srcx, sy + row, p );
141          p += width * 4;
142       }
143       p = tmpImage;
144    }
145    else {
146       tmpImage = NULL;  /* silence compiler warnings */
147       p = NULL;
148    }
149 
150    assert(width < SWRAST_MAX_WIDTH);
151 
152    for (row = 0; row < height; row++, sy += stepy, dy += stepy) {
153       GLvoid *rgba = span.array->attribs[VARYING_SLOT_COL0];
154 
155       /* Get row/span of source pixels */
156       if (overlapping) {
157          /* get from buffered image */
158          memcpy(rgba, p, width * sizeof(GLfloat) * 4);
159          p += width * 4;
160       }
161       else {
162          /* get from framebuffer */
163          _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
164                                  width, srcx, sy, rgba );
165       }
166 
167       if (transferOps) {
168          _mesa_apply_rgba_transfer_ops(ctx, transferOps, width,
169                                        (GLfloat (*)[4]) rgba);
170       }
171 
172       /* Write color span */
173       span.x = destx;
174       span.y = dy;
175       span.end = width;
176       span.array->ChanType = GL_FLOAT;
177       if (zoom) {
178          _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba);
179       }
180       else {
181          _swrast_write_rgba_span(ctx, &span);
182       }
183    }
184 
185    span.array->ChanType = CHAN_TYPE; /* restore */
186 
187    if (overlapping)
188       free(tmpImage);
189 }
190 
191 
192 /**
193  * Convert floating point Z values to integer Z values with pixel transfer's
194  * Z scale and bias.
195  */
196 static void
scale_and_bias_z(struct gl_context * ctx,GLuint width,const GLfloat depth[],GLuint z[])197 scale_and_bias_z(struct gl_context *ctx, GLuint width,
198                  const GLfloat depth[], GLuint z[])
199 {
200    const GLuint depthMax = ctx->DrawBuffer->_DepthMax;
201    GLuint i;
202 
203    if (depthMax <= 0xffffff &&
204        ctx->Pixel.DepthScale == 1.0F &&
205        ctx->Pixel.DepthBias == 0.0F) {
206       /* no scale or bias and no clamping and no worry of overflow */
207       const GLfloat depthMaxF = ctx->DrawBuffer->_DepthMaxF;
208       for (i = 0; i < width; i++) {
209          z[i] = (GLuint) (depth[i] * depthMaxF);
210       }
211    }
212    else {
213       /* need to be careful with overflow */
214       const GLdouble depthMaxF = ctx->DrawBuffer->_DepthMaxF;
215       for (i = 0; i < width; i++) {
216          GLdouble d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
217          d = SATURATE(d) * depthMaxF;
218          if (d >= depthMaxF)
219             z[i] = depthMax;
220          else
221             z[i] = (GLuint) d;
222       }
223    }
224 }
225 
226 
227 
228 /*
229  * TODO: Optimize!!!!
230  */
231 static void
copy_depth_pixels(struct gl_context * ctx,GLint srcx,GLint srcy,GLint width,GLint height,GLint destx,GLint desty)232 copy_depth_pixels( struct gl_context *ctx, GLint srcx, GLint srcy,
233                    GLint width, GLint height,
234                    GLint destx, GLint desty )
235 {
236    struct gl_framebuffer *fb = ctx->ReadBuffer;
237    struct gl_renderbuffer *readRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
238    GLfloat *p, *tmpImage, *depth;
239    GLint sy, dy, stepy;
240    GLint j;
241    const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
242    GLint overlapping;
243    SWspan span;
244 
245    if (!readRb) {
246       /* no readbuffer - OK */
247       return;
248    }
249 
250    INIT_SPAN(span, GL_BITMAP);
251    _swrast_span_default_attribs(ctx, &span);
252    span.arrayMask = SPAN_Z;
253 
254    if (ctx->DrawBuffer == ctx->ReadBuffer) {
255       overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
256                                     ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
257    }
258    else {
259       overlapping = GL_FALSE;
260    }
261 
262    /* Determine if copy should be bottom-to-top or top-to-bottom */
263    if (!overlapping && srcy < desty) {
264       /* top-down  max-to-min */
265       sy = srcy + height - 1;
266       dy = desty + height - 1;
267       stepy = -1;
268    }
269    else {
270       /* bottom-up  min-to-max */
271       sy = srcy;
272       dy = desty;
273       stepy = 1;
274    }
275 
276    if (overlapping) {
277       GLint ssy = sy;
278       tmpImage = malloc(width * height * sizeof(GLfloat));
279       if (!tmpImage) {
280          _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
281          return;
282       }
283       p = tmpImage;
284       for (j = 0; j < height; j++, ssy += stepy) {
285          _swrast_read_depth_span_float(ctx, readRb, width, srcx, ssy, p);
286          p += width;
287       }
288       p = tmpImage;
289    }
290    else {
291       tmpImage = NULL;  /* silence compiler warning */
292       p = NULL;
293    }
294 
295    depth = malloc(width * sizeof(GLfloat));
296    if (!depth) {
297       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels()");
298       goto end;
299    }
300 
301    for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
302       /* get depth values */
303       if (overlapping) {
304          memcpy(depth, p, width * sizeof(GLfloat));
305          p += width;
306       }
307       else {
308          _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth);
309       }
310 
311       /* apply scale and bias */
312       scale_and_bias_z(ctx, width, depth, span.array->z);
313 
314       /* write depth values */
315       span.x = destx;
316       span.y = dy;
317       span.end = width;
318       if (zoom)
319          _swrast_write_zoomed_depth_span(ctx, destx, desty, &span);
320       else
321          _swrast_write_rgba_span(ctx, &span);
322    }
323 
324    free(depth);
325 
326 end:
327    if (overlapping)
328       free(tmpImage);
329 }
330 
331 
332 
333 static void
copy_stencil_pixels(struct gl_context * ctx,GLint srcx,GLint srcy,GLint width,GLint height,GLint destx,GLint desty)334 copy_stencil_pixels( struct gl_context *ctx, GLint srcx, GLint srcy,
335                      GLint width, GLint height,
336                      GLint destx, GLint desty )
337 {
338    struct gl_framebuffer *fb = ctx->ReadBuffer;
339    struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
340    GLint sy, dy, stepy;
341    GLint j;
342    GLubyte *p, *tmpImage, *stencil;
343    const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
344    GLint overlapping;
345 
346    if (!rb) {
347       /* no readbuffer - OK */
348       return;
349    }
350 
351    if (ctx->DrawBuffer == ctx->ReadBuffer) {
352       overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
353                                     ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
354    }
355    else {
356       overlapping = GL_FALSE;
357    }
358 
359    /* Determine if copy should be bottom-to-top or top-to-bottom */
360    if (!overlapping && srcy < desty) {
361       /* top-down  max-to-min */
362       sy = srcy + height - 1;
363       dy = desty + height - 1;
364       stepy = -1;
365    }
366    else {
367       /* bottom-up  min-to-max */
368       sy = srcy;
369       dy = desty;
370       stepy = 1;
371    }
372 
373    if (overlapping) {
374       GLint ssy = sy;
375       tmpImage = malloc(width * height * sizeof(GLubyte));
376       if (!tmpImage) {
377          _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
378          return;
379       }
380       p = tmpImage;
381       for (j = 0; j < height; j++, ssy += stepy) {
382          _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p );
383          p += width;
384       }
385       p = tmpImage;
386    }
387    else {
388       tmpImage = NULL;  /* silence compiler warning */
389       p = NULL;
390    }
391 
392    stencil = malloc(width * sizeof(GLubyte));
393    if (!stencil) {
394       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels()");
395       goto end;
396    }
397 
398    for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
399       /* Get stencil values */
400       if (overlapping) {
401          memcpy(stencil, p, width * sizeof(GLubyte));
402          p += width;
403       }
404       else {
405          _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil );
406       }
407 
408       _mesa_apply_stencil_transfer_ops(ctx, width, stencil);
409 
410       /* Write stencil values */
411       if (zoom) {
412          _swrast_write_zoomed_stencil_span(ctx, destx, desty, width,
413                                            destx, dy, stencil);
414       }
415       else {
416          _swrast_write_stencil_span( ctx, width, destx, dy, stencil );
417       }
418    }
419 
420    free(stencil);
421 
422 end:
423    if (overlapping)
424       free(tmpImage);
425 }
426 
427 
428 /**
429  * Try to do a fast 1:1 blit with memcpy.
430  * \return GL_TRUE if successful, GL_FALSE otherwise.
431  */
432 GLboolean
swrast_fast_copy_pixels(struct gl_context * ctx,struct gl_framebuffer * srcFb,struct gl_framebuffer * dstFb,GLint srcX,GLint srcY,GLsizei width,GLsizei height,GLint dstX,GLint dstY,GLenum type)433 swrast_fast_copy_pixels(struct gl_context *ctx,
434                         struct gl_framebuffer *srcFb,
435                         struct gl_framebuffer *dstFb,
436                         GLint srcX, GLint srcY, GLsizei width, GLsizei height,
437                         GLint dstX, GLint dstY, GLenum type)
438 {
439    struct gl_renderbuffer *srcRb, *dstRb;
440    GLint row;
441    GLuint pixelBytes, widthInBytes;
442    GLubyte *srcMap, *dstMap;
443    GLint srcRowStride, dstRowStride;
444 
445    if (type == GL_COLOR) {
446       if (dstFb->_NumColorDrawBuffers != 1)
447          return GL_FALSE;
448       srcRb = srcFb->_ColorReadBuffer;
449       dstRb = dstFb->_ColorDrawBuffers[0];
450    }
451    else if (type == GL_STENCIL) {
452       srcRb = srcFb->Attachment[BUFFER_STENCIL].Renderbuffer;
453       dstRb = dstFb->Attachment[BUFFER_STENCIL].Renderbuffer;
454    }
455    else if (type == GL_DEPTH) {
456       srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer;
457       dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer;
458    }
459    else {
460       assert(type == GL_DEPTH_STENCIL_EXT);
461       /* XXX correct? */
462       srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer;
463       dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer;
464    }
465 
466    /* src and dst renderbuffers must be same format */
467    if (!srcRb || !dstRb || srcRb->Format != dstRb->Format) {
468       return GL_FALSE;
469    }
470 
471    if (type == GL_STENCIL || type == GL_DEPTH_COMPONENT) {
472       /* can't handle packed depth+stencil here */
473       if (_mesa_is_format_packed_depth_stencil(srcRb->Format) ||
474           _mesa_is_format_packed_depth_stencil(dstRb->Format))
475          return GL_FALSE;
476    }
477    else if (type == GL_DEPTH_STENCIL) {
478       /* can't handle separate depth/stencil buffers */
479       if (srcRb != srcFb->Attachment[BUFFER_STENCIL].Renderbuffer ||
480           dstRb != dstFb->Attachment[BUFFER_STENCIL].Renderbuffer)
481          return GL_FALSE;
482    }
483 
484    /* clipping not supported */
485    if (srcX < 0 || srcX + width > (GLint) srcFb->Width ||
486        srcY < 0 || srcY + height > (GLint) srcFb->Height ||
487        dstX < dstFb->_Xmin || dstX + width > dstFb->_Xmax ||
488        dstY < dstFb->_Ymin || dstY + height > dstFb->_Ymax) {
489       return GL_FALSE;
490    }
491 
492    pixelBytes = _mesa_get_format_bytes(srcRb->Format);
493    widthInBytes = width * pixelBytes;
494 
495    if (srcRb == dstRb) {
496       /* map whole buffer for read/write */
497       /* XXX we could be clever and just map the union region of the
498        * source and dest rects.
499        */
500       GLubyte *map;
501       GLint rowStride;
502 
503       ctx->Driver.MapRenderbuffer(ctx, srcRb, 0, 0,
504                                   srcRb->Width, srcRb->Height,
505                                   GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
506                                   &map, &rowStride, srcFb->FlipY);
507       if (!map) {
508          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
509          return GL_TRUE; /* don't retry with slow path */
510       }
511 
512       srcMap = map + srcY * rowStride + srcX * pixelBytes;
513       dstMap = map + dstY * rowStride + dstX * pixelBytes;
514 
515       /* this handles overlapping copies */
516       if (srcY < dstY) {
517          /* copy in reverse (top->down) order */
518          srcMap += rowStride * (height - 1);
519          dstMap += rowStride * (height - 1);
520          srcRowStride = -rowStride;
521          dstRowStride = -rowStride;
522       }
523       else {
524          /* copy in normal (bottom->up) order */
525          srcRowStride = rowStride;
526          dstRowStride = rowStride;
527       }
528    }
529    else {
530       /* different src/dst buffers */
531       ctx->Driver.MapRenderbuffer(ctx, srcRb, srcX, srcY,
532                                   width, height,
533                                   GL_MAP_READ_BIT, &srcMap, &srcRowStride,
534                                   srcFb->FlipY);
535       if (!srcMap) {
536          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
537          return GL_TRUE; /* don't retry with slow path */
538       }
539       ctx->Driver.MapRenderbuffer(ctx, dstRb, dstX, dstY,
540                                   width, height,
541                                   GL_MAP_WRITE_BIT, &dstMap, &dstRowStride,
542                                   dstFb->FlipY);
543       if (!dstMap) {
544          ctx->Driver.UnmapRenderbuffer(ctx, srcRb);
545          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
546          return GL_TRUE; /* don't retry with slow path */
547       }
548    }
549 
550    for (row = 0; row < height; row++) {
551       /* memmove() in case of overlap */
552       memmove(dstMap, srcMap, widthInBytes);
553       dstMap += dstRowStride;
554       srcMap += srcRowStride;
555    }
556 
557    ctx->Driver.UnmapRenderbuffer(ctx, srcRb);
558    if (dstRb != srcRb) {
559       ctx->Driver.UnmapRenderbuffer(ctx, dstRb);
560    }
561 
562    return GL_TRUE;
563 }
564 
565 
566 /**
567  * Find/map the renderbuffer that we'll be reading from.
568  * The swrast_render_start() function only maps the drawing buffers,
569  * not the read buffer.
570  */
571 static struct gl_renderbuffer *
map_readbuffer(struct gl_context * ctx,GLenum type)572 map_readbuffer(struct gl_context *ctx, GLenum type)
573 {
574    struct gl_framebuffer *fb = ctx->ReadBuffer;
575    struct gl_renderbuffer *rb;
576    struct swrast_renderbuffer *srb;
577 
578    switch (type) {
579    case GL_COLOR:
580       rb = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
581       break;
582    case GL_DEPTH:
583    case GL_DEPTH_STENCIL:
584       rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
585       break;
586    case GL_STENCIL:
587       rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
588       break;
589    default:
590       return NULL;
591    }
592 
593    srb = swrast_renderbuffer(rb);
594 
595    if (!srb || srb->Map) {
596       /* no buffer, or buffer is mapped already, we're done */
597       return NULL;
598    }
599 
600    ctx->Driver.MapRenderbuffer(ctx, rb,
601                                0, 0, rb->Width, rb->Height,
602                                GL_MAP_READ_BIT,
603                                &srb->Map, &srb->RowStride,
604                                fb->FlipY);
605 
606    return rb;
607 }
608 
609 
610 /**
611  * Do software-based glCopyPixels.
612  * By time we get here, all parameters will have been error-checked.
613  */
614 void
_swrast_CopyPixels(struct gl_context * ctx,GLint srcx,GLint srcy,GLsizei width,GLsizei height,GLint destx,GLint desty,GLenum type)615 _swrast_CopyPixels(struct gl_context *ctx,
616                    GLint srcx, GLint srcy, GLsizei width, GLsizei height,
617                    GLint destx, GLint desty, GLenum type)
618 {
619    SWcontext *swrast = SWRAST_CONTEXT(ctx);
620    struct gl_renderbuffer *rb;
621 
622    if (!_mesa_check_conditional_render(ctx))
623       return; /* don't copy */
624 
625    if (swrast->NewState)
626       _swrast_validate_derived( ctx );
627 
628    if (!(SWRAST_CONTEXT(ctx)->_RasterMask != 0x0 ||
629        ctx->Pixel.ZoomX != 1.0F ||
630        ctx->Pixel.ZoomY != 1.0F ||
631        ctx->_ImageTransferState) &&
632       swrast_fast_copy_pixels(ctx, ctx->ReadBuffer, ctx->DrawBuffer,
633                               srcx, srcy, width, height, destx, desty,
634                               type)) {
635       /* all done */
636       return;
637    }
638 
639    swrast_render_start(ctx);
640    rb = map_readbuffer(ctx, type);
641 
642    switch (type) {
643    case GL_COLOR:
644       copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
645       break;
646    case GL_DEPTH:
647       copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
648       break;
649    case GL_STENCIL:
650       copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
651       break;
652    case GL_DEPTH_STENCIL_EXT:
653       /* Copy buffers separately (if the fast copy path wasn't taken) */
654       copy_depth_pixels(ctx, srcx, srcy, width, height, destx, desty);
655       copy_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty);
656       break;
657    default:
658       _mesa_problem(ctx, "unexpected type in _swrast_CopyPixels");
659    }
660 
661    swrast_render_finish(ctx);
662 
663    if (rb) {
664       struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
665       ctx->Driver.UnmapRenderbuffer(ctx, rb);
666       srb->Map = NULL;
667    }
668 }
669