Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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