Home | History | Annotate | Download | only in swrast
      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/macros.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.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, 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 < SWRAST_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, 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->Attachment[BUFFER_DEPTH].Renderbuffer;
    249    GLfloat *p, *tmpImage, *depth;
    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    depth = (GLfloat *) malloc(width * sizeof(GLfloat));
    307    if (!depth) {
    308       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels()");
    309       goto end;
    310    }
    311 
    312    for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
    313       /* get depth values */
    314       if (overlapping) {
    315          memcpy(depth, p, width * sizeof(GLfloat));
    316          p += width;
    317       }
    318       else {
    319          _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth);
    320       }
    321 
    322       /* apply scale and bias */
    323       scale_and_bias_z(ctx, width, depth, span.array->z);
    324 
    325       /* write depth values */
    326       span.x = destx;
    327       span.y = dy;
    328       span.end = width;
    329       if (zoom)
    330          _swrast_write_zoomed_depth_span(ctx, destx, desty, &span);
    331       else
    332          _swrast_write_rgba_span(ctx, &span);
    333    }
    334 
    335    free(depth);
    336 
    337 end:
    338    if (overlapping)
    339       free(tmpImage);
    340 }
    341 
    342 
    343 
    344 static void
    345 copy_stencil_pixels( struct gl_context *ctx, GLint srcx, GLint srcy,
    346                      GLint width, GLint height,
    347                      GLint destx, GLint desty )
    348 {
    349    struct gl_framebuffer *fb = ctx->ReadBuffer;
    350    struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
    351    GLint sy, dy, stepy;
    352    GLint j;
    353    GLubyte *p, *tmpImage, *stencil;
    354    const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
    355    GLint overlapping;
    356 
    357    if (!rb) {
    358       /* no readbuffer - OK */
    359       return;
    360    }
    361 
    362    if (ctx->DrawBuffer == ctx->ReadBuffer) {
    363       overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
    364                                     ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
    365    }
    366    else {
    367       overlapping = GL_FALSE;
    368    }
    369 
    370    /* Determine if copy should be bottom-to-top or top-to-bottom */
    371    if (!overlapping && srcy < desty) {
    372       /* top-down  max-to-min */
    373       sy = srcy + height - 1;
    374       dy = desty + height - 1;
    375       stepy = -1;
    376    }
    377    else {
    378       /* bottom-up  min-to-max */
    379       sy = srcy;
    380       dy = desty;
    381       stepy = 1;
    382    }
    383 
    384    if (overlapping) {
    385       GLint ssy = sy;
    386       tmpImage = (GLubyte *) malloc(width * height * sizeof(GLubyte));
    387       if (!tmpImage) {
    388          _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
    389          return;
    390       }
    391       p = tmpImage;
    392       for (j = 0; j < height; j++, ssy += stepy) {
    393          _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p );
    394          p += width;
    395       }
    396       p = tmpImage;
    397    }
    398    else {
    399       tmpImage = NULL;  /* silence compiler warning */
    400       p = NULL;
    401    }
    402 
    403    stencil = (GLubyte *) malloc(width * sizeof(GLubyte));
    404    if (!stencil) {
    405       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels()");
    406       goto end;
    407    }
    408 
    409    for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
    410       /* Get stencil values */
    411       if (overlapping) {
    412          memcpy(stencil, p, width * sizeof(GLubyte));
    413          p += width;
    414       }
    415       else {
    416          _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil );
    417       }
    418 
    419       _mesa_apply_stencil_transfer_ops(ctx, width, stencil);
    420 
    421       /* Write stencil values */
    422       if (zoom) {
    423          _swrast_write_zoomed_stencil_span(ctx, destx, desty, width,
    424                                            destx, dy, stencil);
    425       }
    426       else {
    427          _swrast_write_stencil_span( ctx, width, destx, dy, stencil );
    428       }
    429    }
    430 
    431    free(stencil);
    432 
    433 end:
    434    if (overlapping)
    435       free(tmpImage);
    436 }
    437 
    438 
    439 /**
    440  * Try to do a fast 1:1 blit with memcpy.
    441  * \return GL_TRUE if successful, GL_FALSE otherwise.
    442  */
    443 GLboolean
    444 swrast_fast_copy_pixels(struct gl_context *ctx,
    445 			GLint srcX, GLint srcY, GLsizei width, GLsizei height,
    446 			GLint dstX, GLint dstY, GLenum type)
    447 {
    448    struct gl_framebuffer *srcFb = ctx->ReadBuffer;
    449    struct gl_framebuffer *dstFb = ctx->DrawBuffer;
    450    struct gl_renderbuffer *srcRb, *dstRb;
    451    GLint row;
    452    GLuint pixelBytes, widthInBytes;
    453    GLubyte *srcMap, *dstMap;
    454    GLint srcRowStride, dstRowStride;
    455 
    456    if (type == GL_COLOR) {
    457       if (dstFb->_NumColorDrawBuffers != 1)
    458          return GL_FALSE;
    459       srcRb = srcFb->_ColorReadBuffer;
    460       dstRb = dstFb->_ColorDrawBuffers[0];
    461    }
    462    else if (type == GL_STENCIL) {
    463       srcRb = srcFb->Attachment[BUFFER_STENCIL].Renderbuffer;
    464       dstRb = dstFb->Attachment[BUFFER_STENCIL].Renderbuffer;
    465    }
    466    else if (type == GL_DEPTH) {
    467       srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer;
    468       dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer;
    469    }
    470    else {
    471       ASSERT(type == GL_DEPTH_STENCIL_EXT);
    472       /* XXX correct? */
    473       srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer;
    474       dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer;
    475    }
    476 
    477    /* src and dst renderbuffers must be same format */
    478    if (!srcRb || !dstRb || srcRb->Format != dstRb->Format) {
    479       return GL_FALSE;
    480    }
    481 
    482    if (type == GL_STENCIL || type == GL_DEPTH_COMPONENT) {
    483       /* can't handle packed depth+stencil here */
    484       if (_mesa_is_format_packed_depth_stencil(srcRb->Format) ||
    485           _mesa_is_format_packed_depth_stencil(dstRb->Format))
    486          return GL_FALSE;
    487    }
    488    else if (type == GL_DEPTH_STENCIL) {
    489       /* can't handle separate depth/stencil buffers */
    490       if (srcRb != srcFb->Attachment[BUFFER_STENCIL].Renderbuffer ||
    491           dstRb != dstFb->Attachment[BUFFER_STENCIL].Renderbuffer)
    492          return GL_FALSE;
    493    }
    494 
    495    /* clipping not supported */
    496    if (srcX < 0 || srcX + width > (GLint) srcFb->Width ||
    497        srcY < 0 || srcY + height > (GLint) srcFb->Height ||
    498        dstX < dstFb->_Xmin || dstX + width > dstFb->_Xmax ||
    499        dstY < dstFb->_Ymin || dstY + height > dstFb->_Ymax) {
    500       return GL_FALSE;
    501    }
    502 
    503    pixelBytes = _mesa_get_format_bytes(srcRb->Format);
    504    widthInBytes = width * pixelBytes;
    505 
    506    if (srcRb == dstRb) {
    507       /* map whole buffer for read/write */
    508       /* XXX we could be clever and just map the union region of the
    509        * source and dest rects.
    510        */
    511       GLubyte *map;
    512       GLint rowStride;
    513 
    514       ctx->Driver.MapRenderbuffer(ctx, srcRb, 0, 0,
    515                                   srcRb->Width, srcRb->Height,
    516                                   GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
    517                                   &map, &rowStride);
    518       if (!map) {
    519          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
    520          return GL_TRUE; /* don't retry with slow path */
    521       }
    522 
    523       srcMap = map + srcY * rowStride + srcX * pixelBytes;
    524       dstMap = map + dstY * rowStride + dstX * pixelBytes;
    525 
    526       /* this handles overlapping copies */
    527       if (srcY < dstY) {
    528          /* copy in reverse (top->down) order */
    529          srcMap += rowStride * (height - 1);
    530          dstMap += rowStride * (height - 1);
    531          srcRowStride = -rowStride;
    532          dstRowStride = -rowStride;
    533       }
    534       else {
    535          /* copy in normal (bottom->up) order */
    536          srcRowStride = rowStride;
    537          dstRowStride = rowStride;
    538       }
    539    }
    540    else {
    541       /* different src/dst buffers */
    542       ctx->Driver.MapRenderbuffer(ctx, srcRb, srcX, srcY,
    543                                   width, height,
    544                                   GL_MAP_READ_BIT, &srcMap, &srcRowStride);
    545       if (!srcMap) {
    546          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
    547          return GL_TRUE; /* don't retry with slow path */
    548       }
    549       ctx->Driver.MapRenderbuffer(ctx, dstRb, dstX, dstY,
    550                                   width, height,
    551                                   GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
    552       if (!dstMap) {
    553          ctx->Driver.UnmapRenderbuffer(ctx, srcRb);
    554          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
    555          return GL_TRUE; /* don't retry with slow path */
    556       }
    557    }
    558 
    559    for (row = 0; row < height; row++) {
    560       /* memmove() in case of overlap */
    561       memmove(dstMap, srcMap, widthInBytes);
    562       dstMap += dstRowStride;
    563       srcMap += srcRowStride;
    564    }
    565 
    566    ctx->Driver.UnmapRenderbuffer(ctx, srcRb);
    567    if (dstRb != srcRb) {
    568       ctx->Driver.UnmapRenderbuffer(ctx, dstRb);
    569    }
    570 
    571    return GL_TRUE;
    572 }
    573 
    574 
    575 /**
    576  * Find/map the renderbuffer that we'll be reading from.
    577  * The swrast_render_start() function only maps the drawing buffers,
    578  * not the read buffer.
    579  */
    580 static struct gl_renderbuffer *
    581 map_readbuffer(struct gl_context *ctx, GLenum type)
    582 {
    583    struct gl_framebuffer *fb = ctx->ReadBuffer;
    584    struct gl_renderbuffer *rb;
    585    struct swrast_renderbuffer *srb;
    586 
    587    switch (type) {
    588    case GL_COLOR:
    589       rb = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
    590       break;
    591    case GL_DEPTH:
    592    case GL_DEPTH_STENCIL:
    593       rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
    594       break;
    595    case GL_STENCIL:
    596       rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
    597       break;
    598    default:
    599       return NULL;
    600    }
    601 
    602    srb = swrast_renderbuffer(rb);
    603 
    604    if (!srb || srb->Map) {
    605       /* no buffer, or buffer is mapped already, we're done */
    606       return NULL;
    607    }
    608 
    609    ctx->Driver.MapRenderbuffer(ctx, rb,
    610                                0, 0, rb->Width, rb->Height,
    611                                GL_MAP_READ_BIT,
    612                                &srb->Map, &srb->RowStride);
    613 
    614    return rb;
    615 }
    616 
    617 
    618 /**
    619  * Do software-based glCopyPixels.
    620  * By time we get here, all parameters will have been error-checked.
    621  */
    622 void
    623 _swrast_CopyPixels( struct gl_context *ctx,
    624 		    GLint srcx, GLint srcy, GLsizei width, GLsizei height,
    625 		    GLint destx, GLint desty, GLenum type )
    626 {
    627    SWcontext *swrast = SWRAST_CONTEXT(ctx);
    628    struct gl_renderbuffer *rb;
    629 
    630    if (!_mesa_check_conditional_render(ctx))
    631       return; /* don't copy */
    632 
    633    if (swrast->NewState)
    634       _swrast_validate_derived( ctx );
    635 
    636    if (!(SWRAST_CONTEXT(ctx)->_RasterMask != 0x0 ||
    637 	 ctx->Pixel.ZoomX != 1.0F ||
    638 	 ctx->Pixel.ZoomY != 1.0F ||
    639 	 ctx->_ImageTransferState) &&
    640        swrast_fast_copy_pixels(ctx, srcx, srcy, width, height, destx, desty,
    641 			       type)) {
    642       /* all done */
    643       return;
    644    }
    645 
    646    swrast_render_start(ctx);
    647    rb = map_readbuffer(ctx, type);
    648 
    649    switch (type) {
    650    case GL_COLOR:
    651       copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
    652       break;
    653    case GL_DEPTH:
    654       copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
    655       break;
    656    case GL_STENCIL:
    657       copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
    658       break;
    659    case GL_DEPTH_STENCIL_EXT:
    660       /* Copy buffers separately (if the fast copy path wasn't taken) */
    661       copy_depth_pixels(ctx, srcx, srcy, width, height, destx, desty);
    662       copy_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty);
    663       break;
    664    default:
    665       _mesa_problem(ctx, "unexpected type in _swrast_CopyPixels");
    666    }
    667 
    668    swrast_render_finish(ctx);
    669 
    670    if (rb) {
    671       struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
    672       ctx->Driver.UnmapRenderbuffer(ctx, rb);
    673       srb->Map = NULL;
    674    }
    675 }
    676