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