Esempio n. 1
0
/**
 * Get colors at x/y positions with clipping.
 * \param type  type of values to return
 */
static void
get_values(struct gl_context *ctx, struct gl_renderbuffer *rb,
           GLuint count, const GLint x[], const GLint y[],
           void *values, GLenum type)
{
   GLuint i;

   for (i = 0; i < count; i++) {
      if (x[i] >= 0 && y[i] >= 0 &&
	  x[i] < (GLint) rb->Width && y[i] < (GLint) rb->Height) {
         /* inside */
         const GLubyte *src = _swrast_pixel_address(rb, x[i], y[i]);

         if (type == GL_UNSIGNED_BYTE) {
            _mesa_unpack_ubyte_rgba_row(rb->Format, 1, src,
                                        (GLubyte (*)[4]) values + i);
         }
         else if (type == GL_FLOAT) {
            _mesa_unpack_rgba_row(rb->Format, 1, src,
                                  (GLfloat (*)[4]) values + i);
         }
         else {
            _mesa_problem(ctx, "unexpected type in get_values()");
         }
      }
   }
}
Esempio n. 2
0
static void
slow_read_rgba_pixels( struct gl_context *ctx,
		       GLint x, GLint y,
		       GLsizei width, GLsizei height,
		       GLenum format, GLenum type,
		       GLvoid *pixels,
		       const struct gl_pixelstore_attrib *packing,
		       GLbitfield transferOps )
{
   struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
   const gl_format rbFormat = _mesa_get_srgb_format_linear(rb->Format);
   void *rgba;
   GLubyte *dst, *map;
   int dstStride, stride, j;

   dstStride = _mesa_image_row_stride(packing, width, format, type);
   dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
					   format, type, 0, 0);

   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
			       &map, &stride);
   if (!map) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
      return;
   }

   rgba = malloc(width * MAX_PIXEL_BYTES);
   if (!rgba)
      goto done;

   for (j = 0; j < height; j++) {
      if (_mesa_is_integer_format(format)) {
	 _mesa_unpack_uint_rgba_row(rbFormat, width, map, (GLuint (*)[4]) rgba);
	 _mesa_pack_rgba_span_int(ctx, width, (GLuint (*)[4]) rgba, format,
                                  type, dst);
      } else {
	 _mesa_unpack_rgba_row(rbFormat, width, map, (GLfloat (*)[4]) rgba);
	 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format,
                                    type, dst, packing, transferOps);
      }
      dst += dstStride;
      map += stride;
   }

   free(rgba);

done:
   ctx->Driver.UnmapRenderbuffer(ctx, rb);
}
Esempio n. 3
0
/**
 * Get row of colors with clipping.
 * \param type  type of values to return
 */
static void
get_row(struct gl_context *ctx, struct gl_renderbuffer *rb,
        GLuint count, GLint x, GLint y,
        GLvoid *values, GLenum type)
{
   GLint skip = 0;
   GLubyte *src;

   if (y < 0 || y >= (GLint) rb->Height)
      return; /* above or below */

   if (x + (GLint) count <= 0 || x >= (GLint) rb->Width)
      return; /* entirely left or right */

   if (x + count > rb->Width) {
      /* right clip */
      GLint clip = x + count - rb->Width;
      count -= clip;
   }

   if (x < 0) {
      /* left clip */
      skip = -x;
      x = 0;
      count -= skip;
   }

   src = _swrast_pixel_address(rb, x, y);

   if (type == GL_UNSIGNED_BYTE) {
      _mesa_unpack_ubyte_rgba_row(rb->Format, count, src,
                                  (GLubyte (*)[4]) values + skip);
   }
   else if (type == GL_FLOAT) {
      _mesa_unpack_rgba_row(rb->Format, count, src,
                            (GLfloat (*)[4]) values + skip);
   }
   else {
      _mesa_problem(ctx, "unexpected type in get_row()");
   }
}
Esempio n. 4
0
/**
 * Read float RGBA pixels from a renderbuffer.  Clipping will be done to
 * prevent reading ouside the buffer's boundaries.
 * \param rgba  the returned colors
 */
void
_swrast_read_rgba_span( struct gl_context *ctx, struct gl_renderbuffer *rb,
                        GLuint n, GLint x, GLint y,
                        GLvoid *rgba)
{
   struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
   GLenum dstType = GL_FLOAT;
   const GLint bufWidth = (GLint) rb->Width;
   const GLint bufHeight = (GLint) rb->Height;

   if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) {
      /* completely above, below, or right */
      /* XXX maybe leave rgba values undefined? */
      memset(rgba, 0, 4 * n * sizeof(GLchan));
   }
   else {
      GLint skip, length;
      GLubyte *src;

      if (x < 0) {
         /* left edge clipping */
         skip = -x;
         length = (GLint) n - skip;
         if (length < 0) {
            /* completely left of window */
            return;
         }
         if (length > bufWidth) {
            length = bufWidth;
         }
      }
      else if ((GLint) (x + n) > bufWidth) {
         /* right edge clipping */
         skip = 0;
         length = bufWidth - x;
         if (length < 0) {
            /* completely to right of window */
            return;
         }
      }
      else {
         /* no clipping */
         skip = 0;
         length = (GLint) n;
      }

      ASSERT(rb);
      ASSERT(rb->_BaseFormat == GL_RGBA ||
	     rb->_BaseFormat == GL_RGB ||
	     rb->_BaseFormat == GL_RG ||
	     rb->_BaseFormat == GL_RED ||
	     rb->_BaseFormat == GL_LUMINANCE ||
	     rb->_BaseFormat == GL_INTENSITY ||
	     rb->_BaseFormat == GL_LUMINANCE_ALPHA ||
	     rb->_BaseFormat == GL_ALPHA);

      assert(srb->Map);

      src = _swrast_pixel_address(rb, x + skip, y);

      if (dstType == GL_UNSIGNED_BYTE) {
         _mesa_unpack_ubyte_rgba_row(rb->Format, length, src,
                                     (GLubyte (*)[4]) rgba + skip);
      }
      else if (dstType == GL_FLOAT) {
         _mesa_unpack_rgba_row(rb->Format, length, src,
                               (GLfloat (*)[4]) rgba + skip);
      }
      else {
         _mesa_problem(ctx, "unexpected type in _swrast_read_rgba_span()");
      }
   }
}
Esempio n. 5
0
/**
 * ColorBuffer = Accum * value
 */
static void
accum_return(struct gl_context *ctx, GLfloat value,
             GLint xpos, GLint ypos, GLint width, GLint height)
{
   struct gl_framebuffer *fb = ctx->DrawBuffer;
   struct gl_renderbuffer *accRb = fb->Attachment[BUFFER_ACCUM].Renderbuffer;
   GLubyte *accMap, *colorMap;
   GLint accRowStride, colorRowStride;
   GLuint buffer;

   /* Map accum buffer */
   ctx->Driver.MapRenderbuffer(ctx, accRb, xpos, ypos, width, height,
                               GL_MAP_READ_BIT,
                               &accMap, &accRowStride);
   if (!accMap) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
      return;
   }

   /* Loop over destination buffers */
   for (buffer = 0; buffer < fb->_NumColorDrawBuffers; buffer++) {
      struct gl_renderbuffer *colorRb = fb->_ColorDrawBuffers[buffer];
      const GLboolean masking = (!ctx->Color.ColorMask[buffer][RCOMP] ||
                                 !ctx->Color.ColorMask[buffer][GCOMP] ||
                                 !ctx->Color.ColorMask[buffer][BCOMP] ||
                                 !ctx->Color.ColorMask[buffer][ACOMP]);
      GLbitfield mappingFlags = GL_MAP_WRITE_BIT;

      if (masking)
         mappingFlags |= GL_MAP_READ_BIT;

      /* Map color buffer */
      ctx->Driver.MapRenderbuffer(ctx, colorRb, xpos, ypos, width, height,
                                  mappingFlags, &colorMap, &colorRowStride);
      if (!colorMap) {
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
         continue;
      }

      if (accRb->Format == MESA_FORMAT_SIGNED_RGBA_16) {
         const GLfloat scale = value / 32767.0f;
         GLint i, j;
         GLfloat (*rgba)[4], (*dest)[4];

         rgba = malloc(width * 4 * sizeof(GLfloat));
         dest = malloc(width * 4 * sizeof(GLfloat));

         if (rgba && dest) {
            for (j = 0; j < height; j++) {
               GLshort *acc = (GLshort *) accMap;

               for (i = 0; i < width; i++) {
                  rgba[i][0] = acc[i * 4 + 0] * scale;
                  rgba[i][1] = acc[i * 4 + 1] * scale;
                  rgba[i][2] = acc[i * 4 + 2] * scale;
                  rgba[i][3] = acc[i * 4 + 3] * scale;
               }

               if (masking) {

                  /* get existing colors from dest buffer */
                  _mesa_unpack_rgba_row(colorRb->Format, width, colorMap, dest);

                  /* use the dest colors where mask[channel] = 0 */
                  if (ctx->Color.ColorMask[buffer][RCOMP] == 0) {
                     for (i = 0; i < width; i++)
                        rgba[i][RCOMP] = dest[i][RCOMP];
                  }
                  if (ctx->Color.ColorMask[buffer][GCOMP] == 0) {
                     for (i = 0; i < width; i++)
                        rgba[i][GCOMP] = dest[i][GCOMP];
                  }
                  if (ctx->Color.ColorMask[buffer][BCOMP] == 0) {
                     for (i = 0; i < width; i++)
                        rgba[i][BCOMP] = dest[i][BCOMP];
                  }
                  if (ctx->Color.ColorMask[buffer][ACOMP] == 0) {
                     for (i = 0; i < width; i++)
                        rgba[i][ACOMP] = dest[i][ACOMP];
                  }
               }

               _mesa_pack_float_rgba_row(colorRb->Format, width,
                                         (const GLfloat (*)[4]) rgba, colorMap);

               accMap += accRowStride;
               colorMap += colorRowStride;
            }
         }
         else {
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
         }
         free(rgba);
         free(dest);
      }
      else {
         /* other types someday? */
      }

      ctx->Driver.UnmapRenderbuffer(ctx, colorRb);
   }

   ctx->Driver.UnmapRenderbuffer(ctx, accRb);
}
Esempio n. 6
0
/**
 * if (load)
 *    Accum = ColorBuf * value
 * else
 *    Accum += ColorBuf * value
 */
static void
accum_or_load(struct gl_context *ctx, GLfloat value,
              GLint xpos, GLint ypos, GLint width, GLint height,
              GLboolean load)
{
   struct gl_renderbuffer *accRb =
      ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer;
   struct gl_renderbuffer *colorRb = ctx->ReadBuffer->_ColorReadBuffer;
   GLubyte *accMap, *colorMap;
   GLint accRowStride, colorRowStride;
   GLbitfield mappingFlags;

   if (!colorRb) {
      /* no read buffer - OK */
      return;
   }

   assert(accRb);

   mappingFlags = GL_MAP_WRITE_BIT;
   if (!load) /* if we're accumulating */
      mappingFlags |= GL_MAP_READ_BIT;

   /* Map accum buffer */
   ctx->Driver.MapRenderbuffer(ctx, accRb, xpos, ypos, width, height,
                               mappingFlags, &accMap, &accRowStride);
   if (!accMap) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
      return;
   }

   /* Map color buffer */
   ctx->Driver.MapRenderbuffer(ctx, colorRb, xpos, ypos, width, height,
                               GL_MAP_READ_BIT,
                               &colorMap, &colorRowStride);
   if (!colorMap) {
      ctx->Driver.UnmapRenderbuffer(ctx, accRb);
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
      return;
   }

   if (accRb->Format == MESA_FORMAT_SIGNED_RGBA_16) {
      const GLfloat scale = value * 32767.0f;
      GLuint i, j;
      GLfloat (*rgba)[4];

      rgba = malloc(width * 4 * sizeof(GLfloat));
      if (rgba) {
         for (j = 0; j < height; j++) {
            GLshort *acc = (GLshort *) accMap;

            /* read colors from source color buffer */
            _mesa_unpack_rgba_row(colorRb->Format, width, colorMap, rgba);

            if (load) {
               for (i = 0; i < width; i++) {
                  acc[i * 4 + 0] = (GLshort) (rgba[i][RCOMP] * scale);
                  acc[i * 4 + 1] = (GLshort) (rgba[i][GCOMP] * scale);
                  acc[i * 4 + 2] = (GLshort) (rgba[i][BCOMP] * scale);
                  acc[i * 4 + 3] = (GLshort) (rgba[i][ACOMP] * scale);
               }
            }
            else {
               /* accumulate */
               for (i = 0; i < width; i++) {
                  acc[i * 4 + 0] += (GLshort) (rgba[i][RCOMP] * scale);
                  acc[i * 4 + 1] += (GLshort) (rgba[i][GCOMP] * scale);
                  acc[i * 4 + 2] += (GLshort) (rgba[i][BCOMP] * scale);
                  acc[i * 4 + 3] += (GLshort) (rgba[i][ACOMP] * scale);
               }
            }

            colorMap += colorRowStride;
            accMap += accRowStride;
         }

         free(rgba);
      }
      else {
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAccum");
      }
   }
   else {
      /* other types someday? */
   }

   ctx->Driver.UnmapRenderbuffer(ctx, accRb);
   ctx->Driver.UnmapRenderbuffer(ctx, colorRb);
}
Esempio n. 7
0
/**
 * Bilinear filtered blit (color only, non-integer values).
 */
static void
blit_linear(struct gl_context *ctx,
            GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
            GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
{
   struct gl_renderbuffer *readRb = ctx->ReadBuffer->_ColorReadBuffer;
   struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0];

   const GLint srcWidth = ABS(srcX1 - srcX0);
   const GLint dstWidth = ABS(dstX1 - dstX0);
   const GLint srcHeight = ABS(srcY1 - srcY0);
   const GLint dstHeight = ABS(dstY1 - dstY0);
   const GLfloat dstHeightF = (GLfloat) dstHeight;

   const GLint srcXpos = MIN2(srcX0, srcX1);
   const GLint srcYpos = MIN2(srcY0, srcY1);
   const GLint dstXpos = MIN2(dstX0, dstX1);
   const GLint dstYpos = MIN2(dstY0, dstY1);

   const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
   const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);

   GLint dstRow;

   GLint pixelSize;
   GLvoid *srcBuffer0, *srcBuffer1;
   GLint srcBufferY0 = -1, srcBufferY1 = -1;
   GLvoid *dstBuffer;

   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);
   }
   else {
      pixelType = GL_FLOAT;
      pixelSize = 4 * sizeof(GLfloat);
   }

   /* Allocate the src/dst row buffers.
    * Keep two adjacent src rows around for bilinear sampling.
    */
   srcBuffer0 = malloc(pixelSize * srcWidth);
   if (!srcBuffer0) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
      return;
   }
   srcBuffer1 = malloc(pixelSize * srcWidth);
   if (!srcBuffer1) {
      free(srcBuffer0);
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
      return;
   }
   dstBuffer = malloc(pixelSize * dstWidth);
   if (!dstBuffer) {
      free(srcBuffer0);
      free(srcBuffer1);
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
      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) {
         free(srcBuffer0);
         free(srcBuffer1);
         free(dstBuffer);
         _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) {
         free(srcBuffer0);
         free(srcBuffer1);
         free(dstBuffer);
         _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);
         free(srcBuffer0);
         free(srcBuffer1);
         free(dstBuffer);
         _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;
      GLint srcRow0 = IFLOOR(srcRow);
      GLint srcRow1 = srcRow0 + 1;
      GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */

      ASSERT(srcRow >= 0);
      ASSERT(srcRow < srcHeight);

      if (srcRow1 == srcHeight) {
         /* last row fudge */
         srcRow1 = srcRow0;
         rowWeight = 0.0;
      }

      if (invertY) {
         srcRow0 = srcHeight - 1 - srcRow0;
         srcRow1 = srcHeight - 1 - srcRow1;
      }

      srcY0 = srcYpos + srcRow0;
      srcY1 = srcYpos + srcRow1;

      /* get the two source rows */
      if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) {
         /* use same source row buffers again */
      }
      else if (srcY0 == srcBufferY1) {
         /* move buffer1 into buffer0 by swapping pointers */
         GLvoid *tmp = srcBuffer0;
         srcBuffer0 = srcBuffer1;
         srcBuffer1 = tmp;
         /* get y1 row */
         {
            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 */
         {
            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 (pixelType == GL_UNSIGNED_BYTE) {
         resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
                                dstBuffer, invertX, rowWeight);
      }
      else {
         resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
                                   dstBuffer, invertX, rowWeight);
      }

      /* store pixel row in destination */
      {
         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);
   }
}
Esempio n. 8
0
/**
 * Blit color, depth or stencil with GL_NEAREST filtering.
 */
static void
blit_nearest(struct gl_context *ctx,
             GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
             GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
             GLbitfield buffer)
{
   struct gl_renderbuffer *readRb, *drawRb;

   const GLint srcWidth = ABS(srcX1 - srcX0);
   const GLint dstWidth = ABS(dstX1 - dstX0);
   const GLint srcHeight = ABS(srcY1 - srcY0);
   const GLint dstHeight = ABS(dstY1 - dstY0);

   const GLint srcXpos = MIN2(srcX0, srcX1);
   const GLint srcYpos = MIN2(srcY0, srcY1);
   const GLint dstXpos = MIN2(dstX0, dstX1);
   const GLint dstYpos = MIN2(dstY0, dstY1);

   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 pixelSize;
   GLvoid *srcBuffer, *dstBuffer;
   GLint prevY = -1;

   typedef void (*resample_func)(GLint srcWidth, GLint dstWidth,
                                 const GLvoid *srcBuffer, GLvoid *dstBuffer,
                                 GLboolean flip);
   resample_func resampleRow;

   switch (buffer) {
   case GL_COLOR_BUFFER_BIT:
      readRb = ctx->ReadBuffer->_ColorReadBuffer;
      drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0];

      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->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->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;
   }

   /* choose row resampler */
   switch (pixelSize) {
   case 1:
      resampleRow = resample_row_1;
      break;
   case 2:
      resampleRow = resample_row_2;
      break;
   case 4:
      resampleRow = resample_row_4;
      break;
   case 8:
      resampleRow = resample_row_8;
      break;
   case 16:
      resampleRow = resample_row_16;
      break;
   default:
      _mesa_problem(ctx, "unexpected pixel size (%d) in blit_nearest",
                    pixelSize);
      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) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
      return;
   }
   dstBuffer = malloc(pixelSize * dstWidth);
   if (!dstBuffer) {
      free(srcBuffer);
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT");
      return;
   }

   for (dstRow = 0; dstRow < dstHeight; dstRow++) {
      GLint srcRow = (dstRow * srcHeight) / dstHeight;
      GLubyte *dstRowStart = dstMap + dstRowStride * dstRow;

      ASSERT(srcRow >= 0);
      ASSERT(srcRow < srcHeight);

      if (invertY) {
         srcRow = srcHeight - 1 - srcRow;
      }

      /* get pixel row from source and resample to match dest width */
      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 = srcRow;
      }

      /* store pixel row in destination */
      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);
   }
}
/**
 * Get an uncompressed color texture image.
 */
static void
get_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions,
                          GLenum format, GLenum type, GLvoid *pixels,
                          struct gl_texture_image *texImage,
                          GLbitfield transferOps)
{
   /* don't want to apply sRGB -> RGB conversion here so override the format */
   const gl_format texFormat =
      _mesa_get_srgb_format_linear(texImage->TexFormat);
   const GLuint width = texImage->Width;
   const GLenum destBaseFormat = _mesa_base_tex_format(ctx, format);
   GLenum rebaseFormat = GL_NONE;
   GLuint height = texImage->Height;
   GLuint depth = texImage->Depth;
   GLuint img, row;
   GLfloat (*rgba)[4];
   GLuint (*rgba_uint)[4];
   GLboolean tex_is_integer = _mesa_is_format_integer_color(texImage->TexFormat);
   GLboolean tex_is_uint = _mesa_is_format_unsigned(texImage->TexFormat);

   /* Allocate buffer for one row of texels */
   rgba = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat));
   rgba_uint = (GLuint (*)[4]) rgba;
   if (!rgba) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
      return;
   }

   if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
      depth = height;
      height = 1;
   }

   if (texImage->_BaseFormat == GL_LUMINANCE ||
       texImage->_BaseFormat == GL_INTENSITY ||
       texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
      /* If a luminance (or intensity) texture is read back as RGB(A), the
       * returned value should be (L,0,0,1), not (L,L,L,1).  Set rebaseFormat
       * here to get G=B=0.
       */
      rebaseFormat = texImage->_BaseFormat;
   }
   else if ((texImage->_BaseFormat == GL_RGBA ||
             texImage->_BaseFormat == GL_RGB ||
             texImage->_BaseFormat == GL_RG) &&
            (destBaseFormat == GL_LUMINANCE ||
             destBaseFormat == GL_LUMINANCE_ALPHA ||
             destBaseFormat == GL_LUMINANCE_INTEGER_EXT ||
             destBaseFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT)) {
      /* If we're reading back an RGB(A) texture as luminance then we need
       * to return L=tex(R).  Note, that's different from glReadPixels which
       * returns L=R+G+B.
       */
      rebaseFormat = GL_LUMINANCE_ALPHA; /* this covers GL_LUMINANCE too */
   }

   for (img = 0; img < depth; img++) {
      GLubyte *srcMap;
      GLint rowstride;

      /* map src texture buffer */
      ctx->Driver.MapTextureImage(ctx, texImage, img,
                                  0, 0, width, height, GL_MAP_READ_BIT,
                                  &srcMap, &rowstride);
      if (srcMap) {
         for (row = 0; row < height; row++) {
            const GLubyte *src = srcMap + row * rowstride;
            void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
                                             width, height, format, type,
                                             img, row, 0);

	    if (tex_is_integer) {
	       _mesa_unpack_uint_rgba_row(texFormat, width, src, rgba_uint);
               if (rebaseFormat)
                  _mesa_rebase_rgba_uint(width, rgba_uint, rebaseFormat);
               if (tex_is_uint) {
                  _mesa_pack_rgba_span_from_uints(ctx, width,
                                                  (GLuint (*)[4]) rgba_uint,
                                                  format, type, dest);
               } else {
                  _mesa_pack_rgba_span_from_ints(ctx, width,
                                                 (GLint (*)[4]) rgba_uint,
                                                 format, type, dest);
               }
	    } else {
	       _mesa_unpack_rgba_row(texFormat, width, src, rgba);
               if (rebaseFormat)
                  _mesa_rebase_rgba_float(width, rgba, rebaseFormat);
	       _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
					  format, type, dest,
					  &ctx->Pack, transferOps);
	    }
	 }

         /* Unmap the src texture buffer */
         ctx->Driver.UnmapTextureImage(ctx, texImage, img);
      }
      else {
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
         break;
      }
   }

   free(rgba);
}