예제 #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);
}
예제 #2
0
/*
 * RGBA copypixels with convolution.
 */
static void
copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
                      GLint width, GLint height, GLint destx, GLint desty)
{
   SWcontext *swrast = SWRAST_CONTEXT(ctx);
   struct gl_renderbuffer *drawRb = NULL;
   GLboolean quick_draw;
   GLint row;
   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
   const GLuint transferOps = ctx->_ImageTransferState;
   GLfloat *dest, *tmpImage, *convImage;
   struct sw_span span;

   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);

   if (ctx->Depth.Test)
      _swrast_span_default_z(ctx, &span);
   if (swrast->_FogEnabled)
      _swrast_span_default_fog(ctx, &span);


   if (SWRAST_CONTEXT(ctx)->_RasterMask == 0
       && !zoom
       && destx >= 0
       && destx + width <= (GLint) ctx->DrawBuffer->Width) {
      quick_draw = GL_TRUE;
      drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];
   }
   else {
      quick_draw = GL_FALSE;
   }

   /* allocate space for GLfloat image */
   tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
   if (!tmpImage) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
      return;
   }
   convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
   if (!convImage) {
      _mesa_free(tmpImage);
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
      return;
   }

   /* read source image */
   dest = tmpImage;
   for (row = 0; row < height; row++) {
      GLchan rgba[MAX_WIDTH][4];
      /* Read GLchan and convert to GLfloat */
      _swrast_read_rgba_span(ctx, ctx->ReadBuffer->_ColorReadBuffer,
                             width, srcx, srcy + row, rgba);
      chan_span_to_float(width, (CONST GLchan (*)[4]) rgba,
                         (GLfloat (*)[4]) dest);
      dest += 4 * width;
   }

   /* do the image transfer ops which preceed convolution */
   for (row = 0; row < height; row++) {
      GLfloat (*rgba)[4] = (GLfloat (*)[4]) (tmpImage + row * width * 4);
      _mesa_apply_rgba_transfer_ops(ctx,
                                    transferOps & IMAGE_PRE_CONVOLUTION_BITS,
                                    width, rgba);
   }

   /* do convolution */
   if (ctx->Pixel.Convolution2DEnabled) {
      _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
   }
   else {
      ASSERT(ctx->Pixel.Separable2DEnabled);
      _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
   }
   _mesa_free(tmpImage);

   /* do remaining post-convolution image transfer ops */
   for (row = 0; row < height; row++) {
      GLfloat (*rgba)[4] = (GLfloat (*)[4]) (convImage + row * width * 4);
      _mesa_apply_rgba_transfer_ops(ctx,
                                    transferOps & IMAGE_POST_CONVOLUTION_BITS,
                                    width, rgba);
   }

   /* write the new image */
   for (row = 0; row < height; row++) {
      const GLfloat *src = convImage + row * width * 4;
      GLint dy;

      /* convert floats back to chan */
      float_span_to_chan(width, (const GLfloat (*)[4]) src, span.array->rgba);

      /* write row to framebuffer */
      dy = desty + row;
      if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) {
         drawRb->PutRow(ctx, drawRb, width, destx, dy, span.array->rgba, NULL);
      }
      else {
         span.x = destx;
         span.y = dy;
         span.end = width;
         if (zoom) {
            _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, 
                                        (CONST GLchan (*)[4])span.array->rgba);
         }
         else {
            _swrast_write_rgba_span(ctx, &span);
         }
      }
   }

   _mesa_free(convImage);
}
예제 #3
0
/*
 * RGBA copypixels
 */
static void
copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
                 GLint width, GLint height, GLint destx, GLint desty)
{
   SWcontext *swrast = SWRAST_CONTEXT(ctx);
   struct gl_renderbuffer *drawRb;
   GLchan *tmpImage,*p;
   GLboolean quick_draw;
   GLint sy, dy, stepy, j;
   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
   GLint overlapping;
   const GLuint transferOps = ctx->_ImageTransferState;
   struct sw_span span;

   if (!ctx->ReadBuffer->_ColorReadBuffer) {
      /* no readbuffer - OK */
      return;
   }

   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);

   if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
      copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty);
      return;
   }

   /* Determine if copy should be done bottom-to-top or top-to-bottom */
   if (srcy < desty) {
      /* top-down  max-to-min */
      sy = srcy + height - 1;
      dy = desty + height - 1;
      stepy = -1;
   }
   else {
      /* bottom-up  min-to-max */
      sy = srcy;
      dy = desty;
      stepy = 1;
   }

   if (ctx->DrawBuffer == ctx->ReadBuffer) {
      overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
                                    ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
   }
   else {
      overlapping = GL_FALSE;
   }

   if (ctx->Depth.Test)
      _swrast_span_default_z(ctx, &span);
   if (swrast->_FogEnabled)
      _swrast_span_default_fog(ctx, &span);

   if (SWRAST_CONTEXT(ctx)->_RasterMask == 0
       && !zoom
       && destx >= 0
       && destx + width <= (GLint) ctx->DrawBuffer->Width) {
      quick_draw = GL_TRUE;
      drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];
   }
   else {
      quick_draw = GL_FALSE;
      drawRb = NULL;
   }

   if (overlapping) {
      GLint ssy = sy;
      tmpImage = (GLchan *) _mesa_malloc(width * height * sizeof(GLchan) * 4);
      if (!tmpImage) {
         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
         return;
      }
      /* read the source image */
      p = tmpImage;
      for (j = 0; j < height; j++, ssy += stepy) {
         _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
                                 width, srcx, ssy, (GLchan (*)[4]) p );
         p += width * 4;
      }
      p = tmpImage;
   }
   else {
      tmpImage = NULL;  /* silence compiler warnings */
      p = NULL;
   }

   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
      /* Get source pixels */
      if (overlapping) {
         /* get from buffered image */
         ASSERT(width < MAX_WIDTH);
         _mesa_memcpy(span.array->rgba, p, width * sizeof(GLchan) * 4);
         p += width * 4;
      }
      else {
         /* get from framebuffer */
         ASSERT(width < MAX_WIDTH);
         _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
                                 width, srcx, sy, span.array->rgba );
      }

      if (transferOps) {
         GLfloat rgbaFloat[MAX_WIDTH][4];
         /* convert to float, transfer, convert back to chan */
         chan_span_to_float(width, (CONST GLchan (*)[4]) span.array->rgba,
                            rgbaFloat);
         _mesa_apply_rgba_transfer_ops(ctx, transferOps, width, rgbaFloat);
         float_span_to_chan(width, (CONST GLfloat (*)[4]) rgbaFloat,
                            span.array->rgba);
      }

      /* Write color span */
      if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) {
         drawRb->PutRow(ctx, drawRb, width, destx, dy, span.array->rgba, NULL);
      }
      else {
         span.x = destx;
         span.y = dy;
         span.end = width;
         if (zoom) {
            _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span,
                                       (CONST GLchan (*)[4]) span.array->rgba);
         }
         else {
            _swrast_write_rgba_span(ctx, &span);
         }
      }
   }

   if (overlapping)
      _mesa_free(tmpImage);
}
예제 #4
0
파일: s_copypix.c 프로젝트: beligit/psx4m
/**
 * RGBA copypixels with convolution.
 */
static void
copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
                      GLint width, GLint height, GLint destx, GLint desty)
{
   SWcontext *swrast = SWRAST_CONTEXT(ctx);
   GLint row;
   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
   const GLbitfield transferOps = ctx->_ImageTransferState;
   const GLboolean sink = (ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink)
      || (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink);
   GLfloat *dest, *tmpImage, *convImage;
   SWspan span;

   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);

   if (ctx->Depth.Test)
      _swrast_span_default_z(ctx, &span);
   if (swrast->_FogEnabled)
      _swrast_span_default_fog(ctx, &span);
   _swrast_span_default_secondary_color(ctx, &span);

   /* allocate space for GLfloat image */
   tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
   if (!tmpImage) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
      return;
   }
   convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
   if (!convImage) {
      _mesa_free(tmpImage);
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
      return;
   }

   /* read source image as float/RGBA */
   dest = tmpImage;
   for (row = 0; row < height; row++) {
      _swrast_read_rgba_span(ctx, ctx->ReadBuffer->_ColorReadBuffer,
                             width, srcx, srcy + row, GL_FLOAT, dest);
      dest += 4 * width;
   }

   /* do the image transfer ops which preceed convolution */
   for (row = 0; row < height; row++) {
      GLfloat (*rgba)[4] = (GLfloat (*)[4]) (tmpImage + row * width * 4);
      _mesa_apply_rgba_transfer_ops(ctx,
                                    transferOps & IMAGE_PRE_CONVOLUTION_BITS,
                                    width, rgba);
   }

   /* do convolution */
   if (ctx->Pixel.Convolution2DEnabled) {
      _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
   }
   else {
      ASSERT(ctx->Pixel.Separable2DEnabled);
      _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
   }
   _mesa_free(tmpImage);

   /* do remaining post-convolution image transfer ops */
   for (row = 0; row < height; row++) {
      GLfloat (*rgba)[4] = (GLfloat (*)[4]) (convImage + row * width * 4);
      _mesa_apply_rgba_transfer_ops(ctx,
                                    transferOps & IMAGE_POST_CONVOLUTION_BITS,
                                    width, rgba);
   }

   if (!sink) {
      /* write the new image */
      for (row = 0; row < height; row++) {
         const GLfloat *src = convImage + row * width * 4;
         GLvoid *rgba = (GLvoid *) span.array->attribs[FRAG_ATTRIB_COL0];

         /* copy convolved colors into span array */
         _mesa_memcpy(rgba, src, width * 4 * sizeof(GLfloat));

         /* write span */
         span.x = destx;
         span.y = desty + row;
         span.end = width;
         span.array->ChanType = GL_FLOAT;
         if (zoom) {
            _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba);
         }
         else {
            _swrast_write_rgba_span(ctx, &span);
         }
      }
      /* restore this */
      span.array->ChanType = CHAN_TYPE;
   }

   _mesa_free(convImage);
}
예제 #5
0
파일: s_copypix.c 프로젝트: beligit/psx4m
/**
 * RGBA copypixels
 */
static void
copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
                 GLint width, GLint height, GLint destx, GLint desty)
{
   SWcontext *swrast = SWRAST_CONTEXT(ctx);
   GLfloat *tmpImage, *p;
   GLint sy, dy, stepy, row;
   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
   GLint overlapping;
   GLuint transferOps = ctx->_ImageTransferState;
   SWspan span;

   if (!ctx->ReadBuffer->_ColorReadBuffer) {
      /* no readbuffer - OK */
      return;
   }

   if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
      copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty);
      return;
   }
   else if (ctx->Pixel.Convolution1DEnabled) {
      /* make sure we don't apply 1D convolution */
      transferOps &= ~(IMAGE_CONVOLUTION_BIT |
                       IMAGE_POST_CONVOLUTION_SCALE_BIAS);
   }

   if (ctx->DrawBuffer == ctx->ReadBuffer) {
      overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
                                    ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
   }
   else {
      overlapping = GL_FALSE;
   }

   /* Determine if copy should be done bottom-to-top or top-to-bottom */
   if (!overlapping && srcy < desty) {
      /* top-down  max-to-min */
      sy = srcy + height - 1;
      dy = desty + height - 1;
      stepy = -1;
   }
   else {
      /* bottom-up  min-to-max */
      sy = srcy;
      dy = desty;
      stepy = 1;
   }

   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
   if (ctx->Depth.Test)
      _swrast_span_default_z(ctx, &span);
   if (swrast->_FogEnabled)
      _swrast_span_default_fog(ctx, &span);
   _swrast_span_default_secondary_color(ctx, &span);

   if (overlapping) {
      tmpImage = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat) * 4);
      if (!tmpImage) {
         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
         return;
      }
      /* read the source image as RGBA/float */
      p = tmpImage;
      for (row = 0; row < height; row++) {
         _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
                                 width, srcx, sy + row, GL_FLOAT, p );
         p += width * 4;
      }
      p = tmpImage;
   }
   else {
      tmpImage = NULL;  /* silence compiler warnings */
      p = NULL;
   }

   ASSERT(width < MAX_WIDTH);

   for (row = 0; row < height; row++, sy += stepy, dy += stepy) {
      GLvoid *rgba = span.array->attribs[FRAG_ATTRIB_COL0];

      /* Get row/span of source pixels */
      if (overlapping) {
         /* get from buffered image */
         _mesa_memcpy(rgba, p, width * sizeof(GLfloat) * 4);
         p += width * 4;
      }
      else {
         /* get from framebuffer */
         _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
                                 width, srcx, sy, GL_FLOAT, rgba );
      }

      if (transferOps) {
         _mesa_apply_rgba_transfer_ops(ctx, transferOps, width,
                                       (GLfloat (*)[4]) rgba);
      }

      /* Write color span */
      span.x = destx;
      span.y = dy;
      span.end = width;
      span.array->ChanType = GL_FLOAT;
      if (zoom) {
         _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba);
      }
      else {
         _swrast_write_rgba_span(ctx, &span);
      }
   }

   span.array->ChanType = CHAN_TYPE; /* restore */

   if (overlapping)
      _mesa_free(tmpImage);
}
예제 #6
0
파일: texgetimage.c 프로젝트: cpp3ds/gl3ds
/**
 * 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 mesa_format texFormat =
      _mesa_get_srgb_format_linear(texImage->TexFormat);
   const GLuint width = texImage->Width;
   GLuint height = texImage->Height;
   GLuint depth = texImage->Depth;
   GLuint img;
   GLboolean dst_is_integer;
   uint32_t dst_format;
   int dst_stride;
   uint8_t rebaseSwizzle[4];
   bool needsRebase;
   void *rgba = NULL;

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

   /* Depending on the base format involved we may need to apply a rebase
    * transform (for example: if we download to a Luminance format we want
    * G=0 and B=0).
    */
   if (texImage->_BaseFormat == GL_LUMINANCE ||
       texImage->_BaseFormat == GL_INTENSITY) {
      needsRebase = true;
      rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X;
      rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO;
      rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO;
      rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_ONE;
   } else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
      needsRebase = true;
      rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X;
      rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO;
      rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO;
      rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_W;
//    } else if (texImage->_BaseFormat != _mesa_get_format_base_format(texFormat)) {
//      needsRebase =
//         _mesa_compute_rgba2base2rgba_component_mapping(texImage->_BaseFormat,
//                                                        rebaseSwizzle);
    } else {
      needsRebase = false;
    }

   /* Describe the dst format */
   dst_is_integer = _mesa_is_enum_format_integer(format);
   dst_format = _mesa_format_from_format_and_type(format, type);
   dst_stride = _mesa_image_row_stride(&ctx->Pack, width, format, type);

   /* 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 then transferOps do not apply.
    */
   assert(!transferOps || (transferOps && !dst_is_integer));
   (void) dst_is_integer; /* silence unused var warning */

   for (img = 0; img < depth; img++) {
      GLubyte *srcMap;
      GLint rowstride;
      GLubyte *img_src;
      void *dest;
      void *src;
      int src_stride;
      uint32_t src_format;

      /* map src texture buffer */
      ctx->Driver.MapTextureImage(ctx, texImage, img,
                                  0, 0, width, height, GL_MAP_READ_BIT,
                                  &srcMap, &rowstride);
      if (!srcMap) {
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
         goto done;
      }

      img_src = srcMap;
      dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
                                 width, height, format, type,
                                 img, 0, 0);

      if (transferOps) {
         uint32_t rgba_format;
         int rgba_stride;
         bool need_convert = false;

         /* We will convert to RGBA float */
//         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 (format == rgba_format) {
            rgba = dest;
         } else if (rgba == NULL) { /* Allocate the RGBA buffer only once */
            need_convert = true;
            rgba = malloc(height * rgba_stride);
            if (!rgba) {
               _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
               ctx->Driver.UnmapTextureImage(ctx, texImage, img);
               return;
            }
         }

//         _mesa_format_convert(rgba, rgba_format, rgba_stride,
//                              img_src, texFormat, rowstride,
//                              width, height,
//                              needsRebase ? rebaseSwizzle : NULL);

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

         /* If we had to rebase, we have already handled that */
         needsRebase = false;

         /* If we were lucky and our RGBA conversion matches the dst format, then
          * we are done.
          */
         if (!need_convert)
            goto do_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 = img_src;
         src_format = texFormat;
         src_stride = rowstride;
      }

      /* Do the conversion to destination format */
//      _mesa_format_convert(dest, dst_format, dst_stride,
//                           src, src_format, src_stride,
//                           width, height,
//                           needsRebase ? rebaseSwizzle : NULL);

   do_swap:
      /* Handle byte swapping if required */
      if (ctx->Pack.SwapBytes) {
         GLint swapSize = _mesa_sizeof_packed_type(type);
         if (swapSize == 2 || swapSize == 4) {
            int swapsPerPixel = _mesa_bytes_per_pixel(format, type) / swapSize;
            assert(_mesa_bytes_per_pixel(format, type) % swapSize == 0);
            if (swapSize == 2)
               _mesa_swap2((GLushort *) dest, width * height * swapsPerPixel);
            else if (swapSize == 4)
               _mesa_swap4((GLuint *) dest, width * height * swapsPerPixel);
         }
      }

      /* Unmap the src texture buffer */
      ctx->Driver.UnmapTextureImage(ctx, texImage, img);
   }

done:
   if (rgba)
      free(rgba);
}
예제 #7
0
/**
 * RGBA copypixels
 */
static void
copy_rgba_pixels(struct gl_context *ctx, GLint srcx, GLint srcy,
                 GLint width, GLint height, GLint destx, GLint desty)
{
    GLfloat *tmpImage, *p;
    GLint sy, dy, stepy, row;
    const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
    GLint overlapping;
    GLuint transferOps = ctx->_ImageTransferState;
    SWspan span;

    if (!ctx->ReadBuffer->_ColorReadBuffer) {
        /* no readbuffer - OK */
        return;
    }

    if (ctx->DrawBuffer == ctx->ReadBuffer) {
        overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
                                      ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
    }
    else {
        overlapping = GL_FALSE;
    }

    /* Determine if copy should be done bottom-to-top or top-to-bottom */
    if (!overlapping && srcy < desty) {
        /* top-down  max-to-min */
        sy = srcy + height - 1;
        dy = desty + height - 1;
        stepy = -1;
    }
    else {
        /* bottom-up  min-to-max */
        sy = srcy;
        dy = desty;
        stepy = 1;
    }

    INIT_SPAN(span, GL_BITMAP);
    _swrast_span_default_attribs(ctx, &span);
    span.arrayMask = SPAN_RGBA;
    span.arrayAttribs = VARYING_BIT_COL0; /* we'll fill in COL0 attrib values */

    if (overlapping) {
        tmpImage = malloc(width * height * sizeof(GLfloat) * 4);
        if (!tmpImage) {
            _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
            return;
        }
        /* read the source image as RGBA/float */
        p = tmpImage;
        for (row = 0; row < height; row++) {
            _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
                                    width, srcx, sy + row, p );
            p += width * 4;
        }
        p = tmpImage;
    }
    else {
        tmpImage = NULL;  /* silence compiler warnings */
        p = NULL;
    }

    ASSERT(width < SWRAST_MAX_WIDTH);

    for (row = 0; row < height; row++, sy += stepy, dy += stepy) {
        GLvoid *rgba = span.array->attribs[VARYING_SLOT_COL0];

        /* Get row/span of source pixels */
        if (overlapping) {
            /* get from buffered image */
            memcpy(rgba, p, width * sizeof(GLfloat) * 4);
            p += width * 4;
        }
        else {
            /* get from framebuffer */
            _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
                                    width, srcx, sy, rgba );
        }

        if (transferOps) {
            _mesa_apply_rgba_transfer_ops(ctx, transferOps, width,
                                          (GLfloat (*)[4]) rgba);
        }

        /* Write color span */
        span.x = destx;
        span.y = dy;
        span.end = width;
        span.array->ChanType = GL_FLOAT;
        if (zoom) {
            _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba);
        }
        else {
            _swrast_write_rgba_span(ctx, &span);
        }
    }

    span.array->ChanType = CHAN_TYPE; /* restore */

    if (overlapping)
        free(tmpImage);
}
예제 #8
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;
}