/* * 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); }
/* * 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); }
/* * 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); }
/** * 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); }
/** * 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); }
/** * 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); }
/** * 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); }
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; }