Home | History | Annotate | Download | only in swrast
      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 #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.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
     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
    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 = CLAMP(d, 0.0, 1.0) * 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
    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
    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
    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);
    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       if (!srcMap) {
    535          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
    536          return GL_TRUE; /* don't retry with slow path */
    537       }
    538       ctx->Driver.MapRenderbuffer(ctx, dstRb, dstX, dstY,
    539                                   width, height,
    540                                   GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
    541       if (!dstMap) {
    542          ctx->Driver.UnmapRenderbuffer(ctx, srcRb);
    543          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
    544          return GL_TRUE; /* don't retry with slow path */
    545       }
    546    }
    547 
    548    for (row = 0; row < height; row++) {
    549       /* memmove() in case of overlap */
    550       memmove(dstMap, srcMap, widthInBytes);
    551       dstMap += dstRowStride;
    552       srcMap += srcRowStride;
    553    }
    554 
    555    ctx->Driver.UnmapRenderbuffer(ctx, srcRb);
    556    if (dstRb != srcRb) {
    557       ctx->Driver.UnmapRenderbuffer(ctx, dstRb);
    558    }
    559 
    560    return GL_TRUE;
    561 }
    562 
    563 
    564 /**
    565  * Find/map the renderbuffer that we'll be reading from.
    566  * The swrast_render_start() function only maps the drawing buffers,
    567  * not the read buffer.
    568  */
    569 static struct gl_renderbuffer *
    570 map_readbuffer(struct gl_context *ctx, GLenum type)
    571 {
    572    struct gl_framebuffer *fb = ctx->ReadBuffer;
    573    struct gl_renderbuffer *rb;
    574    struct swrast_renderbuffer *srb;
    575 
    576    switch (type) {
    577    case GL_COLOR:
    578       rb = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
    579       break;
    580    case GL_DEPTH:
    581    case GL_DEPTH_STENCIL:
    582       rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
    583       break;
    584    case GL_STENCIL:
    585       rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
    586       break;
    587    default:
    588       return NULL;
    589    }
    590 
    591    srb = swrast_renderbuffer(rb);
    592 
    593    if (!srb || srb->Map) {
    594       /* no buffer, or buffer is mapped already, we're done */
    595       return NULL;
    596    }
    597 
    598    ctx->Driver.MapRenderbuffer(ctx, rb,
    599                                0, 0, rb->Width, rb->Height,
    600                                GL_MAP_READ_BIT,
    601                                &srb->Map, &srb->RowStride);
    602 
    603    return rb;
    604 }
    605 
    606 
    607 /**
    608  * Do software-based glCopyPixels.
    609  * By time we get here, all parameters will have been error-checked.
    610  */
    611 void
    612 _swrast_CopyPixels(struct gl_context *ctx,
    613                    GLint srcx, GLint srcy, GLsizei width, GLsizei height,
    614                    GLint destx, GLint desty, GLenum type)
    615 {
    616    SWcontext *swrast = SWRAST_CONTEXT(ctx);
    617    struct gl_renderbuffer *rb;
    618 
    619    if (!_mesa_check_conditional_render(ctx))
    620       return; /* don't copy */
    621 
    622    if (swrast->NewState)
    623       _swrast_validate_derived( ctx );
    624 
    625    if (!(SWRAST_CONTEXT(ctx)->_RasterMask != 0x0 ||
    626        ctx->Pixel.ZoomX != 1.0F ||
    627        ctx->Pixel.ZoomY != 1.0F ||
    628        ctx->_ImageTransferState) &&
    629       swrast_fast_copy_pixels(ctx, ctx->ReadBuffer, ctx->DrawBuffer,
    630                               srcx, srcy, width, height, destx, desty,
    631                               type)) {
    632       /* all done */
    633       return;
    634    }
    635 
    636    swrast_render_start(ctx);
    637    rb = map_readbuffer(ctx, type);
    638 
    639    switch (type) {
    640    case GL_COLOR:
    641       copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
    642       break;
    643    case GL_DEPTH:
    644       copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
    645       break;
    646    case GL_STENCIL:
    647       copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
    648       break;
    649    case GL_DEPTH_STENCIL_EXT:
    650       /* Copy buffers separately (if the fast copy path wasn't taken) */
    651       copy_depth_pixels(ctx, srcx, srcy, width, height, destx, desty);
    652       copy_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty);
    653       break;
    654    default:
    655       _mesa_problem(ctx, "unexpected type in _swrast_CopyPixels");
    656    }
    657 
    658    swrast_render_finish(ctx);
    659 
    660    if (rb) {
    661       struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
    662       ctx->Driver.UnmapRenderbuffer(ctx, rb);
    663       srb->Map = NULL;
    664    }
    665 }
    666