swrast: remove dstType param from _swrast_read_rgba_span()
[mesa.git] / src / mesa / swrast / s_blit.c
index 6ad4f3fbc925f84251bbea1e518a1428522ea24d..6d0b889c1950b44560e900f0f6109d8a9992585d 100644 (file)
@@ -27,6 +27,8 @@
 #include "main/condrender.h"
 #include "main/image.h"
 #include "main/macros.h"
+#include "main/format_unpack.h"
+#include "main/format_pack.h"
 #include "s_context.h"
 
 
@@ -122,10 +124,18 @@ blit_nearest(struct gl_context *ctx,
 
    const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
    const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
-
+   enum mode {
+      DIRECT,
+      UNPACK_RGBA_FLOAT,
+      UNPACK_Z_FLOAT,
+      UNPACK_Z_INT,
+      UNPACK_S,
+   } mode;
+   GLubyte *srcMap, *dstMap;
+   GLint srcRowStride, dstRowStride;
    GLint dstRow;
 
-   GLint comps, pixelSize;
+   GLint pixelSize;
    GLvoid *srcBuffer, *dstBuffer;
    GLint prevY = -1;
 
@@ -138,42 +148,43 @@ blit_nearest(struct gl_context *ctx,
    case GL_COLOR_BUFFER_BIT:
       readRb = ctx->ReadBuffer->_ColorReadBuffer;
       drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0];
-      comps = 4;
+
+      if (readRb->Format == drawRb->Format) {
+        mode = DIRECT;
+        pixelSize = _mesa_get_format_bytes(readRb->Format);
+      } else {
+        mode = UNPACK_RGBA_FLOAT;
+        pixelSize = 16;
+      }
+
       break;
    case GL_DEPTH_BUFFER_BIT:
-      readRb = ctx->ReadBuffer->_DepthBuffer;
-      drawRb = ctx->DrawBuffer->_DepthBuffer;
-      comps = 1;
+      readRb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
+      drawRb = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
+
+      /* Note that for depth/stencil, the formats of src/dst must match.  By
+       * using the core helpers for pack/unpack, we avoid needing to handle
+       * masking for things like DEPTH copies of Z24S8.
+       */
+      if (readRb->Format == MESA_FORMAT_Z32_FLOAT ||
+         readRb->Format == MESA_FORMAT_Z32_FLOAT_X24S8) {
+        mode = UNPACK_Z_FLOAT;
+      } else {
+        mode = UNPACK_Z_INT;
+      }
+      pixelSize = 4;
       break;
    case GL_STENCIL_BUFFER_BIT:
-      readRb = ctx->ReadBuffer->_StencilBuffer;
-      drawRb = ctx->DrawBuffer->_StencilBuffer;
-      comps = 1;
+      readRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
+      drawRb = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
+      mode = UNPACK_S;
+      pixelSize = 1;
       break;
    default:
       _mesa_problem(ctx, "unexpected buffer in blit_nearest()");
       return;
    }
 
-   switch (readRb->DataType) {
-   case GL_UNSIGNED_BYTE:
-      pixelSize = comps * sizeof(GLubyte);
-      break;
-   case GL_UNSIGNED_SHORT:
-      pixelSize = comps * sizeof(GLushort);
-      break;
-   case GL_UNSIGNED_INT:
-      pixelSize = comps * sizeof(GLuint);
-      break;
-   case GL_FLOAT:
-      pixelSize = comps * sizeof(GLfloat);
-      break;
-   default:
-      _mesa_problem(ctx, "unexpected buffer type (0x%x) in blit_nearest",
-                    readRb->DataType);
-      return;
-   }
-
    /* choose row resampler */
    switch (pixelSize) {
    case 1:
@@ -197,6 +208,62 @@ blit_nearest(struct gl_context *ctx,
       return;
    }
 
+   if (readRb == drawRb) {
+      /* map whole buffer for read/write */
+      /* XXX we could be clever and just map the union region of the
+       * source and dest rects.
+       */
+      GLubyte *map;
+      GLint rowStride;
+      GLint formatSize = _mesa_get_format_bytes(readRb->Format);
+
+      ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0,
+                                  readRb->Width, readRb->Height,
+                                  GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
+                                  &map, &rowStride);
+      if (!map) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
+         return;
+      }
+
+      srcMap = map + srcYpos * rowStride + srcXpos * formatSize;
+      dstMap = map + dstYpos * rowStride + dstXpos * formatSize;
+
+      /* this handles overlapping copies */
+      if (srcY0 < dstY0) {
+         /* copy in reverse (top->down) order */
+         srcMap += rowStride * (readRb->Height - 1);
+         dstMap += rowStride * (readRb->Height - 1);
+         srcRowStride = -rowStride;
+         dstRowStride = -rowStride;
+      }
+      else {
+         /* copy in normal (bottom->up) order */
+         srcRowStride = rowStride;
+         dstRowStride = rowStride;
+      }
+   }
+   else {
+      /* different src/dst buffers */
+      ctx->Driver.MapRenderbuffer(ctx, readRb,
+                                 srcXpos, srcYpos,
+                                  srcWidth, srcHeight,
+                                  GL_MAP_READ_BIT, &srcMap, &srcRowStride);
+      if (!srcMap) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
+         return;
+      }
+      ctx->Driver.MapRenderbuffer(ctx, drawRb,
+                                 dstXpos, dstYpos,
+                                  dstWidth, dstHeight,
+                                  GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
+      if (!dstMap) {
+         ctx->Driver.UnmapRenderbuffer(ctx, readRb);
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
+         return;
+      }
+   }
+
    /* allocate the src/dst row buffers */
    srcBuffer = malloc(pixelSize * srcWidth);
    if (!srcBuffer) {
@@ -211,9 +278,8 @@ blit_nearest(struct gl_context *ctx,
    }
 
    for (dstRow = 0; dstRow < dstHeight; dstRow++) {
-      const GLint dstY = dstYpos + dstRow;
       GLint srcRow = (dstRow * srcHeight) / dstHeight;
-      GLint srcY;
+      GLubyte *dstRowStart = dstMap + dstRowStride * dstRow;
 
       ASSERT(srcRow >= 0);
       ASSERT(srcRow < srcHeight);
@@ -222,21 +288,67 @@ blit_nearest(struct gl_context *ctx,
          srcRow = srcHeight - 1 - srcRow;
       }
 
-      srcY = srcYpos + srcRow;
-
       /* get pixel row from source and resample to match dest width */
-      if (prevY != srcY) {
-         readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY, srcBuffer);
+      if (prevY != srcRow) {
+        GLubyte *srcRowStart = srcMap + srcRowStride * srcRow;
+
+        switch (mode) {
+        case DIRECT:
+           memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth);
+           break;
+        case UNPACK_RGBA_FLOAT:
+           _mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart,
+                                 srcBuffer);
+           break;
+        case UNPACK_Z_FLOAT:
+           _mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart,
+                                    srcBuffer);
+           break;
+        case UNPACK_Z_INT:
+           _mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart,
+                                   srcBuffer);
+           break;
+        case UNPACK_S:
+           _mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth,
+                                          srcRowStart, srcBuffer);
+           break;
+        }
+
          (*resampleRow)(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX);
-         prevY = srcY;
+         prevY = srcRow;
       }
 
       /* store pixel row in destination */
-      drawRb->PutRow(ctx, drawRb, dstWidth, dstXpos, dstY, dstBuffer, NULL);
+      switch (mode) {
+      case DIRECT:
+        memcpy(dstRowStart, dstBuffer, pixelSize * srcWidth);
+        break;
+      case UNPACK_RGBA_FLOAT:
+        _mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer,
+                                  dstRowStart);
+        break;
+      case UNPACK_Z_FLOAT:
+        _mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer,
+                               dstRowStart);
+        break;
+      case UNPACK_Z_INT:
+        _mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer,
+                              dstRowStart);
+        break;
+      case UNPACK_S:
+        _mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer,
+                                     dstRowStart);
+        break;
+      }
    }
 
    free(srcBuffer);
    free(dstBuffer);
+
+   ctx->Driver.UnmapRenderbuffer(ctx, readRb);
+   if (drawRb != readRb) {
+      ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
+   }
 }
 
 
@@ -311,9 +423,66 @@ resample_linear_row_ub(GLint srcWidth, GLint dstWidth,
 }
 
 
+/**
+ * Bilinear interpolation of two source rows.  floating point pixels.
+ */
+static void
+resample_linear_row_float(GLint srcWidth, GLint dstWidth,
+                          const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
+                          GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
+{
+   const GLfloat (*srcColor0)[4] = (const GLfloat (*)[4]) srcBuffer0;
+   const GLfloat (*srcColor1)[4] = (const GLfloat (*)[4]) srcBuffer1;
+   GLfloat (*dstColor)[4] = (GLfloat (*)[4]) dstBuffer;
+   const GLfloat dstWidthF = (GLfloat) dstWidth;
+   GLint dstCol;
+
+   for (dstCol = 0; dstCol < dstWidth; dstCol++) {
+      const GLfloat srcCol = (dstCol * srcWidth) / dstWidthF;
+      GLint srcCol0 = IFLOOR(srcCol);
+      GLint srcCol1 = srcCol0 + 1;
+      GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */
+      GLfloat red, green, blue, alpha;
+
+      ASSERT(srcCol0 >= 0);
+      ASSERT(srcCol0 < srcWidth);
+      ASSERT(srcCol1 <= srcWidth);
+
+      if (srcCol1 == srcWidth) {
+         /* last column fudge */
+         srcCol1--;
+         colWeight = 0.0;
+      }
+
+      if (flip) {
+         srcCol0 = srcWidth - 1 - srcCol0;
+         srcCol1 = srcWidth - 1 - srcCol1;
+      }
+
+      red = lerp_2d(colWeight, rowWeight,
+                    srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP],
+                    srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]);
+      green = lerp_2d(colWeight, rowWeight,
+                    srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP],
+                    srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]);
+      blue = lerp_2d(colWeight, rowWeight,
+                    srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP],
+                    srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]);
+      alpha = lerp_2d(colWeight, rowWeight,
+                    srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP],
+                    srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]);
+      
+      dstColor[dstCol][RCOMP] = red;
+      dstColor[dstCol][GCOMP] = green;
+      dstColor[dstCol][BCOMP] = blue;
+      dstColor[dstCol][ACOMP] = alpha;
+   }
+}
+
+
 
 /**
- * Bilinear filtered blit (color only).
+ * Bilinear filtered blit (color only, non-integer values).
  */
 static void
 blit_linear(struct gl_context *ctx,
@@ -344,23 +513,25 @@ blit_linear(struct gl_context *ctx,
    GLint srcBufferY0 = -1, srcBufferY1 = -1;
    GLvoid *dstBuffer;
 
-   switch (readRb->DataType) {
-   case GL_UNSIGNED_BYTE:
+   gl_format readFormat = _mesa_get_srgb_format_linear(readRb->Format);
+   gl_format drawFormat = _mesa_get_srgb_format_linear(drawRb->Format);
+   GLuint bpp = _mesa_get_format_bytes(readFormat);
+
+   GLenum pixelType;
+
+   GLubyte *srcMap, *dstMap;
+   GLint srcRowStride, dstRowStride;
+
+
+   /* Determine datatype for resampling */
+   if (_mesa_get_format_max_bits(readFormat) == 8 &&
+       _mesa_get_format_datatype(readFormat) == GL_UNSIGNED_NORMALIZED) {
+      pixelType = GL_UNSIGNED_BYTE;
       pixelSize = 4 * sizeof(GLubyte);
-      break;
-   case GL_UNSIGNED_SHORT:
-      pixelSize = 4 * sizeof(GLushort);
-      break;
-   case GL_UNSIGNED_INT:
-      pixelSize = 4 * sizeof(GLuint);
-      break;
-   case GL_FLOAT:
+   }
+   else {
+      pixelType = GL_FLOAT;
       pixelSize = 4 * sizeof(GLfloat);
-      break;
-   default:
-      _mesa_problem(ctx, "unexpected buffer type (0x%x) in blit_nearest",
-                    readRb->DataType);
-      return;
    }
 
    /* Allocate the src/dst row buffers.
@@ -385,6 +556,45 @@ blit_linear(struct gl_context *ctx,
       return;
    }
 
+   /*
+    * Map src / dst renderbuffers
+    */
+   if (readRb == drawRb) {
+      /* map whole buffer for read/write */
+      ctx->Driver.MapRenderbuffer(ctx, readRb,
+                                  0, 0, readRb->Width, readRb->Height,
+                                  GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
+                                  &srcMap, &srcRowStride);
+      if (!srcMap) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
+         return;
+      }
+
+      dstMap = srcMap;
+      dstRowStride = srcRowStride;
+   }
+   else {
+      /* different src/dst buffers */
+      /* XXX with a bit of work we could just map the regions to be
+       * read/written instead of the whole buffers.
+       */
+      ctx->Driver.MapRenderbuffer(ctx, readRb,
+                                 0, 0, readRb->Width, readRb->Height,
+                                  GL_MAP_READ_BIT, &srcMap, &srcRowStride);
+      if (!srcMap) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
+         return;
+      }
+      ctx->Driver.MapRenderbuffer(ctx, drawRb,
+                                  0, 0, drawRb->Width, drawRb->Height,
+                                  GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
+      if (!dstMap) {
+         ctx->Driver.UnmapRenderbuffer(ctx, readRb);
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
+         return;
+      }
+   }
+
    for (dstRow = 0; dstRow < dstHeight; dstRow++) {
       const GLint dstY = dstYpos + dstRow;
       const GLfloat srcRow = (dstRow * srcHeight) / dstHeightF;
@@ -419,36 +629,73 @@ blit_linear(struct gl_context *ctx,
          srcBuffer0 = srcBuffer1;
          srcBuffer1 = tmp;
          /* get y1 row */
-         readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY1, srcBuffer1);
+         {
+            GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
+            if (pixelType == GL_UNSIGNED_BYTE) {
+               _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
+                                           src, srcBuffer1);
+            }
+            else {
+               _mesa_unpack_rgba_row(readFormat, srcWidth,
+                                     src, srcBuffer1);
+            }
+         }            
          srcBufferY0 = srcY0;
          srcBufferY1 = srcY1;
       }
       else {
          /* get both new rows */
-         readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY0, srcBuffer0);
-         readRb->GetRow(ctx, readRb, srcWidth, srcXpos, srcY1, srcBuffer1);
+         {
+            GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp;
+            GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
+            if (pixelType == GL_UNSIGNED_BYTE) {
+               _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
+                                           src0, srcBuffer0);
+               _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
+                                           src1, srcBuffer1);
+            }
+            else {
+               _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0);
+               _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1);
+            }
+         }
          srcBufferY0 = srcY0;
          srcBufferY1 = srcY1;
       }
 
-      if (readRb->DataType == GL_UNSIGNED_BYTE) {
+      if (pixelType == GL_UNSIGNED_BYTE) {
          resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
                                 dstBuffer, invertX, rowWeight);
       }
       else {
-         _mesa_problem(ctx, "Unsupported color channel type in sw blit");
-         break;
+         resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
+                                   dstBuffer, invertX, rowWeight);
       }
 
       /* store pixel row in destination */
-      drawRb->PutRow(ctx, drawRb, dstWidth, dstXpos, dstY, dstBuffer, NULL);
+      {
+         GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp;
+         if (pixelType == GL_UNSIGNED_BYTE) {
+            _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
+         }
+         else {
+            _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
+         }
+      }
    }
 
    free(srcBuffer0);
    free(srcBuffer1);
    free(dstBuffer);
+
+   ctx->Driver.UnmapRenderbuffer(ctx, readRb);
+   if (drawRb != readRb) {
+      ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
+   }
 }
 
+
+
 /**
  * Software fallback for glBlitFramebufferEXT().
  */
@@ -503,8 +750,6 @@ _swrast_BlitFramebuffer(struct gl_context *ctx,
         return;
    }
 
-   swrast_render_start(ctx);
-
    if (filter == GL_NEAREST) {
       for (i = 0; i < 3; i++) {
         if (mask & buffers[i]) {
@@ -521,5 +766,4 @@ _swrast_BlitFramebuffer(struct gl_context *ctx,
       }
    }
 
-   swrast_render_finish(ctx);
 }