Ejemplo n.º 1
0
/*
 * Read R, G, B, A, RGB, L, or LA pixels.
 */
static void
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;
   bool dst_is_integer, dst_is_luminance, needs_rebase;
   int dst_stride, src_stride, rb_stride;
   uint32_t dst_format, src_format;
   GLubyte *dst, *map;
   mesa_format rb_format;
   bool needs_rgba;
   void *rgba, *src;
   bool src_is_uint = false;
   uint8_t rebase_swizzle[4];
   struct gl_framebuffer *fb = ctx->ReadBuffer;
   struct gl_renderbuffer *rb = fb->_ColorReadBuffer;

   if (!rb)
      return;

   transferOps = get_readpixels_transfer_ops(ctx, rb->Format, format, type,
                                             GL_FALSE);
   /* Describe the dst format */
   dst_is_integer = _mesa_is_enum_format_integer(format);
   dst_stride = _mesa_image_row_stride(packing, width, format, type);
   dst_format = _mesa_format_from_format_and_type(format, type);
   dst_is_luminance = format == GL_LUMINANCE ||
                      format == GL_LUMINANCE_ALPHA ||
                      format == GL_LUMINANCE_INTEGER_EXT ||
                      format == GL_LUMINANCE_ALPHA_INTEGER_EXT;
   dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
                                           format, type, 0, 0);

   /* Map the source render buffer */
   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
                               &map, &rb_stride);
   if (!map) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
      return;
   }
   rb_format = _mesa_get_srgb_format_linear(rb->Format);

   /*
    * Depending on the base formats involved in the conversion we might need to
    * rebase some values, so for these formats we compute a rebase swizzle.
    */
   if (rb->_BaseFormat == GL_LUMINANCE || rb->_BaseFormat == GL_INTENSITY) {
      needs_rebase = true;
      rebase_swizzle[0] = MESA_FORMAT_SWIZZLE_X;
      rebase_swizzle[1] = MESA_FORMAT_SWIZZLE_ZERO;
      rebase_swizzle[2] = MESA_FORMAT_SWIZZLE_ZERO;
      rebase_swizzle[3] = MESA_FORMAT_SWIZZLE_ONE;
   } else if (rb->_BaseFormat == GL_LUMINANCE_ALPHA) {
      needs_rebase = true;
      rebase_swizzle[0] = MESA_FORMAT_SWIZZLE_X;
      rebase_swizzle[1] = MESA_FORMAT_SWIZZLE_ZERO;
      rebase_swizzle[2] = MESA_FORMAT_SWIZZLE_ZERO;
      rebase_swizzle[3] = MESA_FORMAT_SWIZZLE_W;
   } else if (_mesa_get_format_base_format(rb_format) != rb->_BaseFormat) {
      needs_rebase =
         _mesa_compute_rgba2base2rgba_component_mapping(rb->_BaseFormat,
                                                        rebase_swizzle);
   } else {
      needs_rebase = false;
   }

   /* Since _mesa_format_convert does not handle transferOps we need to handle
    * them before we call the function. This requires to convert to RGBA float
    * first so we can call _mesa_apply_rgba_transfer_ops. If the dst format is
    * integer transferOps do not apply.
    *
    * Converting to luminance also requires converting to RGBA first, so we can
    * then compute luminance values as L=R+G+B. Notice that this is different
    * from GetTexImage, where we compute L=R.
    */
   assert(!transferOps || (transferOps && !dst_is_integer));

   needs_rgba = transferOps || dst_is_luminance;
   rgba = NULL;
   if (needs_rgba) {
      uint32_t rgba_format;
      int rgba_stride;
      bool need_convert;

      /* Convert to RGBA float or int/uint depending on the type of the src */
      if (dst_is_integer) {
         src_is_uint = _mesa_is_format_unsigned(rb_format);
         if (src_is_uint) {
            rgba_format = RGBA32_UINT;
            rgba_stride = width * 4 * sizeof(GLuint);
         } else {
            rgba_format = RGBA32_INT;
            rgba_stride = width * 4 * sizeof(GLint);
         }
      } else {
         rgba_format = RGBA32_FLOAT;
         rgba_stride = width * 4 * sizeof(GLfloat);
      }

      /* If we are lucky and the dst format matches the RGBA format we need to
       * convert to, then we can convert directly into the dst buffer and avoid
       * the final conversion/copy from the rgba buffer to the dst buffer.
       */
      if (dst_format == rgba_format) {
         need_convert = false;
         rgba = dst;
      } else {
         need_convert = true;
         rgba = malloc(height * rgba_stride);
         if (!rgba) {
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
            goto done_unmap;
         }
      }

      /* Convert to RGBA now */
      _mesa_format_convert(rgba, rgba_format, rgba_stride,
                           map, rb_format, rb_stride,
                           width, height,
                           needs_rebase ? rebase_swizzle : NULL);

      /* Handle transfer ops if necessary */
      if (transferOps)
         _mesa_apply_rgba_transfer_ops(ctx, transferOps, width * height, rgba);

      /* If we had to rebase, we have already taken care of that */
      needs_rebase = false;

      /* If we were lucky and our RGBA conversion matches the dst format, then
       * we are done.
       */
      if (!need_convert)
         goto done_swap;

      /* Otherwise, we need to convert from RGBA to dst next */
      src = rgba;
      src_format = rgba_format;
      src_stride = rgba_stride;
   } else {
      /* No RGBA conversion needed, convert directly to dst */
      src = map;
      src_format = rb_format;
      src_stride = rb_stride;
   }

   /* Do the conversion.
    *
    * If the dst format is Luminance, we need to do the conversion by computing
    * L=R+G+B values.
    */
   if (!dst_is_luminance) {
      _mesa_format_convert(dst, dst_format, dst_stride,
                           src, src_format, src_stride,
                           width, height,
                           needs_rebase ? rebase_swizzle : NULL);
   } else if (!dst_is_integer) {
      /* Compute float Luminance values from RGBA float */
      int luminance_stride, luminance_bytes;
      void *luminance;
      uint32_t luminance_format;

      luminance_stride = width * sizeof(GL_FLOAT);
      if (format == GL_LUMINANCE_ALPHA)
         luminance_stride *= 2;
      luminance_bytes = height * luminance_stride;
      luminance = malloc(luminance_bytes);
      if (!luminance) {
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
         free(rgba);
         goto done_unmap;
      }
      _mesa_pack_luminance_from_rgba_float(width * height, src,
                                           luminance, format, transferOps);

      /* Convert from Luminance float to dst (this will hadle type conversion
       * from float to the type of dst if necessary)
       */
      luminance_format = _mesa_format_from_format_and_type(format, GL_FLOAT);
      _mesa_format_convert(dst, dst_format, dst_stride,
                           luminance, luminance_format, luminance_stride,
                           width, height, NULL);
   } else {
      _mesa_pack_luminance_from_rgba_integer(width * height, src, !src_is_uint,
                                             dst, format, type);
   }

   if (rgba)
      free(rgba);

done_swap:
   /* Handle byte swapping if required */
   if (packing->SwapBytes) {
      int components = _mesa_components_in_format(format);
      GLint swapSize = _mesa_sizeof_packed_type(type);
      if (swapSize == 2)
         _mesa_swap2((GLushort *) dst, width * height * components);
      else if (swapSize == 4)
         _mesa_swap4((GLuint *) dst, width * height * components);
   }

done_unmap:
   ctx->Driver.UnmapRenderbuffer(ctx, rb);
}
Ejemplo n.º 2
0
static GLboolean
texstore_rgba(TEXSTORE_PARAMS)
{
   void *tempImage = NULL, *tempRGBA = NULL;
   int srcRowStride, img;
   GLubyte *src, *dst;
   uint32_t srcMesaFormat;
   uint8_t rebaseSwizzle[4];
   bool needRebase;
   bool transferOpsDone = false;

   /* We have to handle MESA_FORMAT_YCBCR manually because it is a special case
    * and _mesa_format_convert does not support it. In this case the we only
    * allow conversions between YCBCR formats and it is mostly a memcpy.
    */
   if (dstFormat == MESA_FORMAT_YCBCR || dstFormat == MESA_FORMAT_YCBCR_REV) {
      return _mesa_texstore_ycbcr(ctx, dims, baseInternalFormat,
                                  dstFormat, dstRowStride, dstSlices,
                                  srcWidth, srcHeight, srcDepth,
                                  srcFormat, srcType, srcAddr,
                                  srcPacking);
   }

   /* We have to deal with GL_COLOR_INDEX manually because
    * _mesa_format_convert does not handle this format. So what we do here is
    * convert it to RGBA ubyte first and then convert from that to dst as usual.
    */
   if (srcFormat == GL_COLOR_INDEX) {
      /* Notice that this will already handle byte swapping if necessary */
      tempImage =
         _mesa_unpack_color_index_to_rgba_ubyte(ctx, dims,
                                                srcAddr, srcFormat, srcType,
                                                srcWidth, srcHeight, srcDepth,
                                                srcPacking,
                                                ctx->_ImageTransferState);
      if (!tempImage)
         return GL_FALSE;

      /* _mesa_unpack_color_index_to_rgba_ubyte has handled transferops
       * if needed.
       */
      transferOpsDone = true;

      /* Now we only have to adjust our src info for a conversion from
       * the RGBA ubyte and then we continue as usual.
       */
      srcAddr = tempImage;
      srcFormat = GL_RGBA;
      srcType = GL_UNSIGNED_BYTE;
   } else if (srcPacking->SwapBytes) {
      /* We have to handle byte-swapping scenarios before calling
       * _mesa_format_convert
       */
      GLint swapSize = _mesa_sizeof_packed_type(srcType);
      if (swapSize == 2 || swapSize == 4) {
         int bytesPerPixel = _mesa_bytes_per_pixel(srcFormat, srcType);
         int swapsPerPixel = bytesPerPixel / swapSize;
         int elementCount = srcWidth * srcHeight * srcDepth;
         assert(bytesPerPixel % swapSize == 0);
         tempImage = malloc(elementCount * bytesPerPixel);
         if (!tempImage)
            return GL_FALSE;
         if (swapSize == 2)
            _mesa_swap2_copy(tempImage, (GLushort *) srcAddr,
                             elementCount * swapsPerPixel);
         else
            _mesa_swap4_copy(tempImage, (GLuint *) srcAddr,
                             elementCount * swapsPerPixel);
         srcAddr = tempImage;
      }
   }

   srcRowStride =
      _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType);

   srcMesaFormat = _mesa_format_from_format_and_type(srcFormat, srcType);
   dstFormat = _mesa_get_srgb_format_linear(dstFormat);

   /* If we have transferOps then we need to convert to RGBA float first,
      then apply transferOps, then do the conversion to dst
    */
   if (!transferOpsDone &&
       _mesa_texstore_needs_transfer_ops(ctx, baseInternalFormat, dstFormat)) {
      /* Allocate RGBA float image */
      int elementCount = srcWidth * srcHeight * srcDepth;
      tempRGBA = malloc(4 * elementCount * sizeof(float));
      if (!tempRGBA) {
         free(tempImage);
         free(tempRGBA);
         return GL_FALSE;
      }

      /* Convert from src to RGBA float */
      src = (GLubyte *) srcAddr;
      dst = (GLubyte *) tempRGBA;
      for (img = 0; img < srcDepth; img++) {
         _mesa_format_convert(dst, RGBA32_FLOAT, 4 * srcWidth * sizeof(float),
                              src, srcMesaFormat, srcRowStride,
                              srcWidth, srcHeight, NULL);
         src += srcHeight * srcRowStride;
         dst += srcHeight * 4 * srcWidth * sizeof(float);
      }

      /* Apply transferOps */
      _mesa_apply_rgba_transfer_ops(ctx, ctx->_ImageTransferState, elementCount,
                                    (float(*)[4]) tempRGBA);

      /* Now we have to adjust our src info for a conversion from
       * the RGBA float image and then we continue as usual.
       */
      srcAddr = tempRGBA;
      srcFormat = GL_RGBA;
      srcType = GL_FLOAT;
      srcRowStride = srcWidth * 4 * sizeof(float);
      srcMesaFormat = RGBA32_FLOAT;
   }

   src = (GLubyte *)
      _mesa_image_address(dims, srcPacking, srcAddr, srcWidth, srcHeight,
                          srcFormat, srcType, 0, 0, 0);

   if (_mesa_get_format_base_format(dstFormat) != baseInternalFormat) {
      needRebase =
         _mesa_compute_rgba2base2rgba_component_mapping(baseInternalFormat,
                                                        rebaseSwizzle);
   } else {
      needRebase = false;
   }

   for (img = 0; img < srcDepth; img++) {
      _mesa_format_convert(dstSlices[img], dstFormat, dstRowStride,
                           src, srcMesaFormat, srcRowStride,
                           srcWidth, srcHeight,
                           needRebase ? rebaseSwizzle : NULL);
      src += srcHeight * srcRowStride;
   }

   free(tempImage);
   free(tempRGBA);

   return GL_TRUE;
}