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 "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.