Home | History | Annotate | Download | only in swrast
      1 /*
      2  * Mesa 3-D graphics library
      3  * Version:  6.5
      4  *
      5  * Copyright (C) 1999-2006  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/condrender.h"
     28 #include "main/image.h"
     29 #include "main/macros.h"
     30 #include "main/format_unpack.h"
     31 #include "main/format_pack.h"
     32 #include "s_context.h"
     33 
     34 
     35 #define ABS(X)   ((X) < 0 ? -(X) : (X))
     36 
     37 
     38 /**
     39  * Generate a row resampler function for GL_NEAREST mode.
     40  */
     41 #define RESAMPLE(NAME, PIXELTYPE, SIZE)			\
     42 static void						\
     43 NAME(GLint srcWidth, GLint dstWidth,			\
     44      const GLvoid *srcBuffer, GLvoid *dstBuffer,	\
     45      GLboolean flip)					\
     46 {							\
     47    const PIXELTYPE *src = (const PIXELTYPE *) srcBuffer;\
     48    PIXELTYPE *dst = (PIXELTYPE *) dstBuffer;		\
     49    GLint dstCol;					\
     50 							\
     51    if (flip) {						\
     52       for (dstCol = 0; dstCol < dstWidth; dstCol++) {	\
     53          GLint srcCol = (dstCol * srcWidth) / dstWidth;	\
     54          ASSERT(srcCol >= 0);				\
     55          ASSERT(srcCol < srcWidth);			\
     56          srcCol = srcWidth - 1 - srcCol; /* flip */	\
     57          if (SIZE == 1) {				\
     58             dst[dstCol] = src[srcCol];			\
     59          }						\
     60          else if (SIZE == 2) {				\
     61             dst[dstCol*2+0] = src[srcCol*2+0];		\
     62             dst[dstCol*2+1] = src[srcCol*2+1];		\
     63          }						\
     64          else if (SIZE == 4) {				\
     65             dst[dstCol*4+0] = src[srcCol*4+0];		\
     66             dst[dstCol*4+1] = src[srcCol*4+1];		\
     67             dst[dstCol*4+2] = src[srcCol*4+2];		\
     68             dst[dstCol*4+3] = src[srcCol*4+3];		\
     69          }						\
     70       }							\
     71    }							\
     72    else {						\
     73       for (dstCol = 0; dstCol < dstWidth; dstCol++) {	\
     74          GLint srcCol = (dstCol * srcWidth) / dstWidth;	\
     75          ASSERT(srcCol >= 0);				\
     76          ASSERT(srcCol < srcWidth);			\
     77          if (SIZE == 1) {				\
     78             dst[dstCol] = src[srcCol];			\
     79          }						\
     80          else if (SIZE == 2) {				\
     81             dst[dstCol*2+0] = src[srcCol*2+0];		\
     82             dst[dstCol*2+1] = src[srcCol*2+1];		\
     83          }						\
     84          else if (SIZE == 4) {				\
     85             dst[dstCol*4+0] = src[srcCol*4+0];		\
     86             dst[dstCol*4+1] = src[srcCol*4+1];		\
     87             dst[dstCol*4+2] = src[srcCol*4+2];		\
     88             dst[dstCol*4+3] = src[srcCol*4+3];		\
     89          }						\
     90       }							\
     91    }							\
     92 }
     93 
     94 /**
     95  * Resamplers for 1, 2, 4, 8 and 16-byte pixels.
     96  */
     97 RESAMPLE(resample_row_1, GLubyte, 1)
     98 RESAMPLE(resample_row_2, GLushort, 1)
     99 RESAMPLE(resample_row_4, GLuint, 1)
    100 RESAMPLE(resample_row_8, GLuint, 2)
    101 RESAMPLE(resample_row_16, GLuint, 4)
    102 
    103 
    104 /**
    105  * Blit color, depth or stencil with GL_NEAREST filtering.
    106  */
    107 static void
    108 blit_nearest(struct gl_context *ctx,
    109              GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
    110              GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
    111              GLbitfield buffer)
    112 {
    113    struct gl_renderbuffer *readRb, *drawRb;
    114 
    115    const GLint srcWidth = ABS(srcX1 - srcX0);
    116    const GLint dstWidth = ABS(dstX1 - dstX0);
    117    const GLint srcHeight = ABS(srcY1 - srcY0);
    118    const GLint dstHeight = ABS(dstY1 - dstY0);
    119 
    120    const GLint srcXpos = MIN2(srcX0, srcX1);
    121    const GLint srcYpos = MIN2(srcY0, srcY1);
    122    const GLint dstXpos = MIN2(dstX0, dstX1);
    123    const GLint dstYpos = MIN2(dstY0, dstY1);
    124 
    125    const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
    126    const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
    127    enum mode {
    128       DIRECT,
    129       UNPACK_RGBA_FLOAT,
    130       UNPACK_Z_FLOAT,
    131       UNPACK_Z_INT,
    132       UNPACK_S,
    133    } mode;
    134    GLubyte *srcMap, *dstMap;
    135    GLint srcRowStride, dstRowStride;
    136    GLint dstRow;
    137 
    138    GLint pixelSize;
    139    GLvoid *srcBuffer, *dstBuffer;
    140    GLint prevY = -1;
    141 
    142    typedef void (*resample_func)(GLint srcWidth, GLint dstWidth,
    143                                  const GLvoid *srcBuffer, GLvoid *dstBuffer,
    144                                  GLboolean flip);
    145    resample_func resampleRow;
    146 
    147    switch (buffer) {
    148    case GL_COLOR_BUFFER_BIT:
    149       readRb = ctx->ReadBuffer->_ColorReadBuffer;
    150       drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0];
    151 
    152       if (readRb->Format == drawRb->Format) {
    153 	 mode = DIRECT;
    154 	 pixelSize = _mesa_get_format_bytes(readRb->Format);
    155       } else {
    156 	 mode = UNPACK_RGBA_FLOAT;
    157 	 pixelSize = 16;
    158       }
    159 
    160       break;
    161    case GL_DEPTH_BUFFER_BIT:
    162       readRb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
    163       drawRb = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
    164 
    165       /* Note that for depth/stencil, the formats of src/dst must match.  By
    166        * using the core helpers for pack/unpack, we avoid needing to handle
    167        * masking for things like DEPTH copies of Z24S8.
    168        */
    169       if (readRb->Format == MESA_FORMAT_Z32_FLOAT ||
    170 	  readRb->Format == MESA_FORMAT_Z32_FLOAT_X24S8) {
    171 	 mode = UNPACK_Z_FLOAT;
    172       } else {
    173 	 mode = UNPACK_Z_INT;
    174       }
    175       pixelSize = 4;
    176       break;
    177    case GL_STENCIL_BUFFER_BIT:
    178       readRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
    179       drawRb = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
    180       mode = UNPACK_S;
    181       pixelSize = 1;
    182       break;
    183    default:
    184       _mesa_problem(ctx, "unexpected buffer in blit_nearest()");
    185       return;
    186    }
    187 
    188    /* choose row resampler */
    189    switch (pixelSize) {
    190    case 1:
    191       resampleRow = resample_row_1;
    192       break;
    193    case 2:
    194       resampleRow = resample_row_2;
    195       break;
    196    case 4:
    197       resampleRow = resample_row_4;
    198       break;
    199    case 8:
    200       resampleRow = resample_row_8;
    201       break;
    202    case 16:
    203       resampleRow = resample_row_16;
    204       break;
    205    default:
    206       _mesa_problem(ctx, "unexpected pixel size (%d) in blit_nearest",
    207                     pixelSize);
    208       return;
    209    }
    210 
    211    if (readRb == drawRb) {
    212       /* map whole buffer for read/write */
    213       /* XXX we could be clever and just map the union region of the
    214        * source and dest rects.
    215        */
    216       GLubyte *map;
    217       GLint rowStride;
    218       GLint formatSize = _mesa_get_format_bytes(readRb->Format);
    219 
    220       ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0,
    221                                   readRb->Width, readRb->Height,
    222                                   GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
    223                                   &map, &rowStride);
    224       if (!map) {
    225          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
    226          return;
    227       }
    228 
    229       srcMap = map + srcYpos * rowStride + srcXpos * formatSize;
    230       dstMap = map + dstYpos * rowStride + dstXpos * formatSize;
    231 
    232       /* this handles overlapping copies */
    233       if (srcY0 < dstY0) {
    234          /* copy in reverse (top->down) order */
    235          srcMap += rowStride * (readRb->Height - 1);
    236          dstMap += rowStride * (readRb->Height - 1);
    237          srcRowStride = -rowStride;
    238          dstRowStride = -rowStride;
    239       }
    240       else {
    241          /* copy in normal (bottom->up) order */
    242          srcRowStride = rowStride;
    243          dstRowStride = rowStride;
    244       }
    245    }
    246    else {
    247       /* different src/dst buffers */
    248       ctx->Driver.MapRenderbuffer(ctx, readRb,
    249 				  srcXpos, srcYpos,
    250                                   srcWidth, srcHeight,
    251                                   GL_MAP_READ_BIT, &srcMap, &srcRowStride);
    252       if (!srcMap) {
    253          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
    254          return;
    255       }
    256       ctx->Driver.MapRenderbuffer(ctx, drawRb,
    257 				  dstXpos, dstYpos,
    258                                   dstWidth, dstHeight,
    259                                   GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
    260       if (!dstMap) {
    261          ctx->Driver.UnmapRenderbuffer(ctx, readRb);
    262          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
    263          return;
    264       }
    265    }
    266 
    267    /* allocate the src/dst row buffers */
    268    srcBuffer = malloc(pixelSize * srcWidth);
    269    if (!srcBuffer) {
    270       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
    271       return;
    272    }
    273    dstBuffer = malloc(pixelSize * dstWidth);
    274    if (!dstBuffer) {
    275       free(srcBuffer);
    276       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
    277       return;
    278    }
    279 
    280    for (dstRow = 0; dstRow < dstHeight; dstRow++) {
    281       GLint srcRow = (dstRow * srcHeight) / dstHeight;
    282       GLubyte *dstRowStart = dstMap + dstRowStride * dstRow;
    283 
    284       ASSERT(srcRow >= 0);
    285       ASSERT(srcRow < srcHeight);
    286 
    287       if (invertY) {
    288          srcRow = srcHeight - 1 - srcRow;
    289       }
    290 
    291       /* get pixel row from source and resample to match dest width */
    292       if (prevY != srcRow) {
    293 	 GLubyte *srcRowStart = srcMap + srcRowStride * srcRow;
    294 
    295 	 switch (mode) {
    296 	 case DIRECT:
    297 	    memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth);
    298 	    break;
    299 	 case UNPACK_RGBA_FLOAT:
    300 	    _mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart,
    301 				  srcBuffer);
    302 	    break;
    303 	 case UNPACK_Z_FLOAT:
    304 	    _mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart,
    305 				     srcBuffer);
    306 	    break;
    307 	 case UNPACK_Z_INT:
    308 	    _mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart,
    309 				    srcBuffer);
    310 	    break;
    311 	 case UNPACK_S:
    312 	    _mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth,
    313 					   srcRowStart, srcBuffer);
    314 	    break;
    315 	 }
    316 
    317          (*resampleRow)(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX);
    318          prevY = srcRow;
    319       }
    320 
    321       /* store pixel row in destination */
    322       switch (mode) {
    323       case DIRECT:
    324 	 memcpy(dstRowStart, dstBuffer, pixelSize * srcWidth);
    325 	 break;
    326       case UNPACK_RGBA_FLOAT:
    327 	 _mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer,
    328 				   dstRowStart);
    329 	 break;
    330       case UNPACK_Z_FLOAT:
    331 	 _mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer,
    332 				dstRowStart);
    333 	 break;
    334       case UNPACK_Z_INT:
    335 	 _mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer,
    336 			       dstRowStart);
    337 	 break;
    338       case UNPACK_S:
    339 	 _mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer,
    340 				      dstRowStart);
    341 	 break;
    342       }
    343    }
    344 
    345    free(srcBuffer);
    346    free(dstBuffer);
    347 
    348    ctx->Driver.UnmapRenderbuffer(ctx, readRb);
    349    if (drawRb != readRb) {
    350       ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
    351    }
    352 }
    353 
    354 
    355 
    356 #define LERP(T, A, B)  ( (A) + (T) * ((B) - (A)) )
    357 
    358 static inline GLfloat
    359 lerp_2d(GLfloat a, GLfloat b,
    360         GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11)
    361 {
    362    const GLfloat temp0 = LERP(a, v00, v10);
    363    const GLfloat temp1 = LERP(a, v01, v11);
    364    return LERP(b, temp0, temp1);
    365 }
    366 
    367 
    368 /**
    369  * Bilinear interpolation of two source rows.
    370  * GLubyte pixels.
    371  */
    372 static void
    373 resample_linear_row_ub(GLint srcWidth, GLint dstWidth,
    374                        const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
    375                        GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
    376 {
    377    const GLubyte (*srcColor0)[4] = (const GLubyte (*)[4]) srcBuffer0;
    378    const GLubyte (*srcColor1)[4] = (const GLubyte (*)[4]) srcBuffer1;
    379    GLubyte (*dstColor)[4] = (GLubyte (*)[4]) dstBuffer;
    380    const GLfloat dstWidthF = (GLfloat) dstWidth;
    381    GLint dstCol;
    382 
    383    for (dstCol = 0; dstCol < dstWidth; dstCol++) {
    384       const GLfloat srcCol = (dstCol * srcWidth) / dstWidthF;
    385       GLint srcCol0 = IFLOOR(srcCol);
    386       GLint srcCol1 = srcCol0 + 1;
    387       GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */
    388       GLfloat red, green, blue, alpha;
    389 
    390       ASSERT(srcCol0 >= 0);
    391       ASSERT(srcCol0 < srcWidth);
    392       ASSERT(srcCol1 <= srcWidth);
    393 
    394       if (srcCol1 == srcWidth) {
    395          /* last column fudge */
    396          srcCol1--;
    397          colWeight = 0.0;
    398       }
    399 
    400       if (flip) {
    401          srcCol0 = srcWidth - 1 - srcCol0;
    402          srcCol1 = srcWidth - 1 - srcCol1;
    403       }
    404 
    405       red = lerp_2d(colWeight, rowWeight,
    406                     srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP],
    407                     srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]);
    408       green = lerp_2d(colWeight, rowWeight,
    409                     srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP],
    410                     srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]);
    411       blue = lerp_2d(colWeight, rowWeight,
    412                     srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP],
    413                     srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]);
    414       alpha = lerp_2d(colWeight, rowWeight,
    415                     srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP],
    416                     srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]);
    417 
    418       dstColor[dstCol][RCOMP] = IFLOOR(red);
    419       dstColor[dstCol][GCOMP] = IFLOOR(green);
    420       dstColor[dstCol][BCOMP] = IFLOOR(blue);
    421       dstColor[dstCol][ACOMP] = IFLOOR(alpha);
    422    }
    423 }
    424 
    425 
    426 /**
    427  * Bilinear interpolation of two source rows.  floating point pixels.
    428  */
    429 static void
    430 resample_linear_row_float(GLint srcWidth, GLint dstWidth,
    431                           const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
    432                           GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
    433 {
    434    const GLfloat (*srcColor0)[4] = (const GLfloat (*)[4]) srcBuffer0;
    435    const GLfloat (*srcColor1)[4] = (const GLfloat (*)[4]) srcBuffer1;
    436    GLfloat (*dstColor)[4] = (GLfloat (*)[4]) dstBuffer;
    437    const GLfloat dstWidthF = (GLfloat) dstWidth;
    438    GLint dstCol;
    439 
    440    for (dstCol = 0; dstCol < dstWidth; dstCol++) {
    441       const GLfloat srcCol = (dstCol * srcWidth) / dstWidthF;
    442       GLint srcCol0 = IFLOOR(srcCol);
    443       GLint srcCol1 = srcCol0 + 1;
    444       GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */
    445       GLfloat red, green, blue, alpha;
    446 
    447       ASSERT(srcCol0 >= 0);
    448       ASSERT(srcCol0 < srcWidth);
    449       ASSERT(srcCol1 <= srcWidth);
    450 
    451       if (srcCol1 == srcWidth) {
    452          /* last column fudge */
    453          srcCol1--;
    454          colWeight = 0.0;
    455       }
    456 
    457       if (flip) {
    458          srcCol0 = srcWidth - 1 - srcCol0;
    459          srcCol1 = srcWidth - 1 - srcCol1;
    460       }
    461 
    462       red = lerp_2d(colWeight, rowWeight,
    463                     srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP],
    464                     srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]);
    465       green = lerp_2d(colWeight, rowWeight,
    466                     srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP],
    467                     srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]);
    468       blue = lerp_2d(colWeight, rowWeight,
    469                     srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP],
    470                     srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]);
    471       alpha = lerp_2d(colWeight, rowWeight,
    472                     srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP],
    473                     srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]);
    474 
    475       dstColor[dstCol][RCOMP] = red;
    476       dstColor[dstCol][GCOMP] = green;
    477       dstColor[dstCol][BCOMP] = blue;
    478       dstColor[dstCol][ACOMP] = alpha;
    479    }
    480 }
    481 
    482 
    483 
    484 /**
    485  * Bilinear filtered blit (color only, non-integer values).
    486  */
    487 static void
    488 blit_linear(struct gl_context *ctx,
    489             GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
    490             GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
    491 {
    492    struct gl_renderbuffer *readRb = ctx->ReadBuffer->_ColorReadBuffer;
    493    struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0];
    494 
    495    const GLint srcWidth = ABS(srcX1 - srcX0);
    496    const GLint dstWidth = ABS(dstX1 - dstX0);
    497    const GLint srcHeight = ABS(srcY1 - srcY0);
    498    const GLint dstHeight = ABS(dstY1 - dstY0);
    499    const GLfloat dstHeightF = (GLfloat) dstHeight;
    500 
    501    const GLint srcXpos = MIN2(srcX0, srcX1);
    502    const GLint srcYpos = MIN2(srcY0, srcY1);
    503    const GLint dstXpos = MIN2(dstX0, dstX1);
    504    const GLint dstYpos = MIN2(dstY0, dstY1);
    505 
    506    const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
    507    const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
    508 
    509    GLint dstRow;
    510 
    511    GLint pixelSize;
    512    GLvoid *srcBuffer0, *srcBuffer1;
    513    GLint srcBufferY0 = -1, srcBufferY1 = -1;
    514    GLvoid *dstBuffer;
    515 
    516    gl_format readFormat = _mesa_get_srgb_format_linear(readRb->Format);
    517    gl_format drawFormat = _mesa_get_srgb_format_linear(drawRb->Format);
    518    GLuint bpp = _mesa_get_format_bytes(readFormat);
    519 
    520    GLenum pixelType;
    521 
    522    GLubyte *srcMap, *dstMap;
    523    GLint srcRowStride, dstRowStride;
    524 
    525 
    526    /* Determine datatype for resampling */
    527    if (_mesa_get_format_max_bits(readFormat) == 8 &&
    528        _mesa_get_format_datatype(readFormat) == GL_UNSIGNED_NORMALIZED) {
    529       pixelType = GL_UNSIGNED_BYTE;
    530       pixelSize = 4 * sizeof(GLubyte);
    531    }
    532    else {
    533       pixelType = GL_FLOAT;
    534       pixelSize = 4 * sizeof(GLfloat);
    535    }
    536 
    537    /* Allocate the src/dst row buffers.
    538     * Keep two adjacent src rows around for bilinear sampling.
    539     */
    540    srcBuffer0 = malloc(pixelSize * srcWidth);
    541    if (!srcBuffer0) {
    542       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
    543       return;
    544    }
    545    srcBuffer1 = malloc(pixelSize * srcWidth);
    546    if (!srcBuffer1) {
    547       free(srcBuffer0);
    548       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
    549       return;
    550    }
    551    dstBuffer = malloc(pixelSize * dstWidth);
    552    if (!dstBuffer) {
    553       free(srcBuffer0);
    554       free(srcBuffer1);
    555       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
    556       return;
    557    }
    558 
    559    /*
    560     * Map src / dst renderbuffers
    561     */
    562    if (readRb == drawRb) {
    563       /* map whole buffer for read/write */
    564       ctx->Driver.MapRenderbuffer(ctx, readRb,
    565                                   0, 0, readRb->Width, readRb->Height,
    566                                   GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
    567                                   &srcMap, &srcRowStride);
    568       if (!srcMap) {
    569          free(srcBuffer0);
    570          free(srcBuffer1);
    571          free(dstBuffer);
    572          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
    573          return;
    574       }
    575 
    576       dstMap = srcMap;
    577       dstRowStride = srcRowStride;
    578    }
    579    else {
    580       /* different src/dst buffers */
    581       /* XXX with a bit of work we could just map the regions to be
    582        * read/written instead of the whole buffers.
    583        */
    584       ctx->Driver.MapRenderbuffer(ctx, readRb,
    585 				  0, 0, readRb->Width, readRb->Height,
    586                                   GL_MAP_READ_BIT, &srcMap, &srcRowStride);
    587       if (!srcMap) {
    588          free(srcBuffer0);
    589          free(srcBuffer1);
    590          free(dstBuffer);
    591          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
    592          return;
    593       }
    594       ctx->Driver.MapRenderbuffer(ctx, drawRb,
    595                                   0, 0, drawRb->Width, drawRb->Height,
    596                                   GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
    597       if (!dstMap) {
    598          ctx->Driver.UnmapRenderbuffer(ctx, readRb);
    599          free(srcBuffer0);
    600          free(srcBuffer1);
    601          free(dstBuffer);
    602          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
    603          return;
    604       }
    605    }
    606 
    607    for (dstRow = 0; dstRow < dstHeight; dstRow++) {
    608       const GLint dstY = dstYpos + dstRow;
    609       const GLfloat srcRow = (dstRow * srcHeight) / dstHeightF;
    610       GLint srcRow0 = IFLOOR(srcRow);
    611       GLint srcRow1 = srcRow0 + 1;
    612       GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */
    613 
    614       ASSERT(srcRow >= 0);
    615       ASSERT(srcRow < srcHeight);
    616 
    617       if (srcRow1 == srcHeight) {
    618          /* last row fudge */
    619          srcRow1 = srcRow0;
    620          rowWeight = 0.0;
    621       }
    622 
    623       if (invertY) {
    624          srcRow0 = srcHeight - 1 - srcRow0;
    625          srcRow1 = srcHeight - 1 - srcRow1;
    626       }
    627 
    628       srcY0 = srcYpos + srcRow0;
    629       srcY1 = srcYpos + srcRow1;
    630 
    631       /* get the two source rows */
    632       if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) {
    633          /* use same source row buffers again */
    634       }
    635       else if (srcY0 == srcBufferY1) {
    636          /* move buffer1 into buffer0 by swapping pointers */
    637          GLvoid *tmp = srcBuffer0;
    638          srcBuffer0 = srcBuffer1;
    639          srcBuffer1 = tmp;
    640          /* get y1 row */
    641          {
    642             GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
    643             if (pixelType == GL_UNSIGNED_BYTE) {
    644                _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
    645                                            src, srcBuffer1);
    646             }
    647             else {
    648                _mesa_unpack_rgba_row(readFormat, srcWidth,
    649                                      src, srcBuffer1);
    650             }
    651          }
    652          srcBufferY0 = srcY0;
    653          srcBufferY1 = srcY1;
    654       }
    655       else {
    656          /* get both new rows */
    657          {
    658             GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp;
    659             GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
    660             if (pixelType == GL_UNSIGNED_BYTE) {
    661                _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
    662                                            src0, srcBuffer0);
    663                _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
    664                                            src1, srcBuffer1);
    665             }
    666             else {
    667                _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0);
    668                _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1);
    669             }
    670          }
    671          srcBufferY0 = srcY0;
    672          srcBufferY1 = srcY1;
    673       }
    674 
    675       if (pixelType == GL_UNSIGNED_BYTE) {
    676          resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
    677                                 dstBuffer, invertX, rowWeight);
    678       }
    679       else {
    680          resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
    681                                    dstBuffer, invertX, rowWeight);
    682       }
    683 
    684       /* store pixel row in destination */
    685       {
    686          GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp;
    687          if (pixelType == GL_UNSIGNED_BYTE) {
    688             _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
    689          }
    690          else {
    691             _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
    692          }
    693       }
    694    }
    695 
    696    free(srcBuffer0);
    697    free(srcBuffer1);
    698    free(dstBuffer);
    699 
    700    ctx->Driver.UnmapRenderbuffer(ctx, readRb);
    701    if (drawRb != readRb) {
    702       ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
    703    }
    704 }
    705 
    706 
    707 
    708 /**
    709  * Software fallback for glBlitFramebufferEXT().
    710  */
    711 void
    712 _swrast_BlitFramebuffer(struct gl_context *ctx,
    713                         GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
    714                         GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
    715                         GLbitfield mask, GLenum filter)
    716 {
    717    static const GLbitfield buffers[3] = {
    718       GL_COLOR_BUFFER_BIT,
    719       GL_DEPTH_BUFFER_BIT,
    720       GL_STENCIL_BUFFER_BIT
    721    };
    722    static const GLenum buffer_enums[3] = {
    723       GL_COLOR,
    724       GL_DEPTH,
    725       GL_STENCIL,
    726    };
    727    GLint i;
    728 
    729    if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1,
    730                         &dstX0, &dstY0, &dstX1, &dstY1)) {
    731       return;
    732    }
    733 
    734    if (SWRAST_CONTEXT(ctx)->NewState)
    735       _swrast_validate_derived(ctx);
    736 
    737    /* First, try covering whatever buffers possible using the fast 1:1 copy
    738     * path.
    739     */
    740    if (srcX1 - srcX0 == dstX1 - dstX0 &&
    741        srcY1 - srcY0 == dstY1 - dstY0 &&
    742        srcX0 < srcX1 &&
    743        srcY0 < srcY1 &&
    744        dstX0 < dstX1 &&
    745        dstY0 < dstY1) {
    746       for (i = 0; i < 3; i++) {
    747          if (mask & buffers[i]) {
    748 	    if (swrast_fast_copy_pixels(ctx,
    749 					srcX0, srcY0,
    750 					srcX1 - srcX0, srcY1 - srcY0,
    751 					dstX0, dstY0,
    752 					buffer_enums[i])) {
    753 	       mask &= ~buffers[i];
    754 	    }
    755 	 }
    756       }
    757 
    758       if (!mask)
    759 	 return;
    760    }
    761 
    762    if (filter == GL_NEAREST) {
    763       for (i = 0; i < 3; i++) {
    764 	 if (mask & buffers[i]) {
    765 	    blit_nearest(ctx,  srcX0, srcY0, srcX1, srcY1,
    766 			 dstX0, dstY0, dstX1, dstY1, buffers[i]);
    767 	 }
    768       }
    769    }
    770    else {
    771       ASSERT(filter == GL_LINEAR);
    772       if (mask & GL_COLOR_BUFFER_BIT) {  /* depth/stencil not allowed */
    773 	 blit_linear(ctx,  srcX0, srcY0, srcX1, srcY1,
    774 		     dstX0, dstY0, dstX1, dstY1);
    775       }
    776    }
    777 
    778 }
    779