-/* $Id: s_readpix.c,v 1.16 2002/09/21 17:34:56 brianp Exp $ */
-
/*
* Mesa 3-D graphics library
- * Version: 4.1
+ * Version: 7.0.3
*
- * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
+ * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
#include "glheader.h"
+#include "bufferobj.h"
#include "colormac.h"
#include "convolve.h"
#include "context.h"
#include "feedback.h"
#include "image.h"
#include "macros.h"
-#include "mem.h"
+#include "imports.h"
#include "pixel.h"
+#include "state.h"
-#include "s_alphabuf.h"
#include "s_context.h"
#include "s_depth.h"
#include "s_span.h"
#include "s_stencil.h"
-
/*
* Read a block of color index pixels.
*/
GLenum type, GLvoid *pixels,
const struct gl_pixelstore_attrib *packing )
{
- SWcontext *swrast = SWRAST_CONTEXT(ctx);
- GLint i, readWidth;
+ struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
+ GLint i;
- /* error checking */
- if (ctx->Visual.rgbMode) {
- _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
+ if (!rb)
return;
- }
- _swrast_use_read_buffer(ctx);
-
- readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
+ /* width should never be > MAX_WIDTH since we did clipping earlier */
+ ASSERT(width <= MAX_WIDTH);
/* process image row by row */
for (i = 0; i < height; i++) {
GLuint index[MAX_WIDTH];
GLvoid *dest;
+ ASSERT(rb->DataType == GL_UNSIGNED_INT);
+ rb->GetRow(ctx, rb, width, x, y + i, index);
- (*swrast->Driver.ReadCI32Span)(ctx, readWidth, x, y + i, index);
-
- dest = _mesa_image_address(packing, pixels, width, height,
- GL_COLOR_INDEX, type, 0, i, 0);
+ dest = _mesa_image_address2d(packing, pixels, width, height,
+ GL_COLOR_INDEX, type, i, 0);
- _mesa_pack_index_span(ctx, readWidth, type, dest, index,
+ _mesa_pack_index_span(ctx, width, type, dest, index,
&ctx->Pack, ctx->_ImageTransferState);
}
-
- _swrast_use_draw_buffer(ctx);
}
+/**
+ * Read pixels for format=GL_DEPTH_COMPONENT.
+ */
static void
read_depth_pixels( GLcontext *ctx,
GLint x, GLint y,
GLenum type, GLvoid *pixels,
const struct gl_pixelstore_attrib *packing )
{
- GLint readWidth;
- GLboolean bias_or_scale;
-
- /* Error checking */
- if (ctx->Visual.depthBits <= 0) {
- /* No depth buffer */
- _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
- return;
- }
-
- readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
+ struct gl_framebuffer *fb = ctx->ReadBuffer;
+ struct gl_renderbuffer *rb = fb->_DepthBuffer;
+ const GLboolean biasOrScale
+ = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
- if (type != GL_BYTE &&
- type != GL_UNSIGNED_BYTE &&
- type != GL_SHORT &&
- type != GL_UNSIGNED_SHORT &&
- type != GL_INT &&
- type != GL_UNSIGNED_INT &&
- type != GL_FLOAT) {
- _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels(depth type)");
+ if (!rb)
return;
- }
- bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
+ /* clipping should have been done already */
+ ASSERT(x >= 0);
+ ASSERT(y >= 0);
+ ASSERT(x + width <= (GLint) rb->Width);
+ ASSERT(y + height <= (GLint) rb->Height);
+ /* width should never be > MAX_WIDTH since we did clipping earlier */
+ ASSERT(width <= MAX_WIDTH);
- if (type==GL_UNSIGNED_SHORT && ctx->Visual.depthBits == 16
- && !bias_or_scale && !packing->SwapBytes) {
+ if (type == GL_UNSIGNED_SHORT && fb->Visual.depthBits == 16
+ && !biasOrScale && !packing->SwapBytes) {
/* Special case: directly read 16-bit unsigned depth values. */
GLint j;
- for (j=0;j<height;j++,y++) {
- GLdepth depth[MAX_WIDTH];
- GLushort *dst = (GLushort*) _mesa_image_address( packing, pixels,
- width, height, GL_DEPTH_COMPONENT, type, 0, j, 0 );
- GLint i;
- _mesa_read_depth_span(ctx, width, x, y, depth);
- for (i = 0; i < width; i++)
- dst[i] = depth[i];
+ ASSERT(rb->InternalFormat == GL_DEPTH_COMPONENT16);
+ ASSERT(rb->DataType == GL_UNSIGNED_SHORT);
+ for (j = 0; j < height; j++, y++) {
+ void *dest =_mesa_image_address2d(packing, pixels, width, height,
+ GL_DEPTH_COMPONENT, type, j, 0);
+ rb->GetRow(ctx, rb, width, x, y, dest);
}
}
- else if (type==GL_UNSIGNED_INT && ctx->Visual.depthBits == 32
- && !bias_or_scale && !packing->SwapBytes) {
+ else if (type == GL_UNSIGNED_INT && fb->Visual.depthBits == 24
+ && !biasOrScale && !packing->SwapBytes) {
+ /* Special case: directly read 24-bit unsigned depth values. */
+ GLint j;
+ ASSERT(rb->InternalFormat == GL_DEPTH_COMPONENT24);
+ ASSERT(rb->DataType == GL_UNSIGNED_INT);
+ for (j = 0; j < height; j++, y++) {
+ GLuint *dest = (GLuint *)
+ _mesa_image_address2d(packing, pixels, width, height,
+ GL_DEPTH_COMPONENT, type, j, 0);
+ GLint k;
+ rb->GetRow(ctx, rb, width, x, y, dest);
+ /* convert range from 24-bit to 32-bit */
+ for (k = 0; k < width; k++) {
+ /* Note: put MSByte of 24-bit value into LSByte */
+ dest[k] = (dest[k] << 8) | ((dest[k] >> 16) & 0xff);
+ }
+ }
+ }
+ else if (type == GL_UNSIGNED_INT && fb->Visual.depthBits == 32
+ && !biasOrScale && !packing->SwapBytes) {
/* Special case: directly read 32-bit unsigned depth values. */
GLint j;
- for (j=0;j<height;j++,y++) {
- GLdepth *dst = (GLdepth *) _mesa_image_address( packing, pixels,
- width, height, GL_DEPTH_COMPONENT, type, 0, j, 0 );
- _mesa_read_depth_span(ctx, width, x, y, dst);
+ ASSERT(rb->InternalFormat == GL_DEPTH_COMPONENT32);
+ ASSERT(rb->DataType == GL_UNSIGNED_INT);
+ for (j = 0; j < height; j++, y++) {
+ void *dest = _mesa_image_address2d(packing, pixels, width, height,
+ GL_DEPTH_COMPONENT, type, j, 0);
+ rb->GetRow(ctx, rb, width, x, y, dest);
}
}
else {
/* General case (slower) */
GLint j;
- for (j=0;j<height;j++,y++) {
- GLfloat depth[MAX_WIDTH];
- GLvoid *dest;
-
- _mesa_read_depth_span_float(ctx, readWidth, x, y, depth);
-
- dest = _mesa_image_address(packing, pixels, width, height,
- GL_DEPTH_COMPONENT, type, 0, j, 0);
-
- _mesa_pack_depth_span(ctx, readWidth, (GLdepth *) dest, type,
- depth, &ctx->Pack);
+ for (j = 0; j < height; j++, y++) {
+ GLfloat depthValues[MAX_WIDTH];
+ GLvoid *dest = _mesa_image_address2d(packing, pixels, width, height,
+ GL_DEPTH_COMPONENT, type, j, 0);
+ _swrast_read_depth_span_float(ctx, rb, width, x, y, depthValues);
+ _mesa_pack_depth_span(ctx, width, dest, type, depthValues, packing);
}
}
}
-
+/**
+ * Read pixels for format=GL_STENCIL_INDEX.
+ */
static void
read_stencil_pixels( GLcontext *ctx,
GLint x, GLint y,
GLenum type, GLvoid *pixels,
const struct gl_pixelstore_attrib *packing )
{
- GLint j, readWidth;
-
- if (type != GL_BYTE &&
- type != GL_UNSIGNED_BYTE &&
- type != GL_SHORT &&
- type != GL_UNSIGNED_SHORT &&
- type != GL_INT &&
- type != GL_UNSIGNED_INT &&
- type != GL_FLOAT &&
- type != GL_BITMAP) {
- _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels(stencil type)");
- return;
- }
-
- readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
+ struct gl_framebuffer *fb = ctx->ReadBuffer;
+ struct gl_renderbuffer *rb = fb->_StencilBuffer;
+ GLint j;
- if (ctx->Visual.stencilBits <= 0) {
- /* No stencil buffer */
- _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
+ if (!rb)
return;
- }
+
+ /* width should never be > MAX_WIDTH since we did clipping earlier */
+ ASSERT(width <= MAX_WIDTH);
/* process image row by row */
for (j=0;j<height;j++,y++) {
GLvoid *dest;
GLstencil stencil[MAX_WIDTH];
- _mesa_read_stencil_span(ctx, readWidth, x, y, stencil);
+ _swrast_read_stencil_span(ctx, rb, width, x, y, stencil);
- dest = _mesa_image_address(packing, pixels, width, height,
- GL_STENCIL_INDEX, type, 0, j, 0);
+ dest = _mesa_image_address2d(packing, pixels, width, height,
+ GL_STENCIL_INDEX, type, j, 0);
- _mesa_pack_stencil_span(ctx, readWidth, type, dest, stencil, &ctx->Pack);
+ _mesa_pack_stencil_span(ctx, width, type, dest, stencil, packing);
}
}
-/*
- * Optimized glReadPixels for particular pixel formats:
- * GL_UNSIGNED_BYTE, GL_RGBA
- * when pixel scaling, biasing and mapping are disabled.
+/**
+ * Optimized glReadPixels for particular pixel formats when pixel
+ * scaling, biasing, mapping, etc. are disabled.
+ * \return GL_TRUE if success, GL_FALSE if unable to do the readpixels
*/
static GLboolean
-read_fast_rgba_pixels( GLcontext *ctx,
+fast_read_rgba_pixels( GLcontext *ctx,
GLint x, GLint y,
GLsizei width, GLsizei height,
GLenum format, GLenum type,
GLvoid *pixels,
- const struct gl_pixelstore_attrib *packing )
+ const struct gl_pixelstore_attrib *packing,
+ GLbitfield transferOps)
{
- SWcontext *swrast = SWRAST_CONTEXT(ctx);
- /* can't do scale, bias, mapping, etc */
- if (ctx->_ImageTransferState)
- return GL_FALSE;
+ struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
- /* can't do fancy pixel packing */
- if (packing->Alignment != 1 || packing->SwapBytes || packing->LsbFirst)
+ if (!rb)
return GL_FALSE;
- {
- GLint srcX = x;
- GLint srcY = y;
- GLint readWidth = width; /* actual width read */
- GLint readHeight = height; /* actual height read */
- GLint skipPixels = packing->SkipPixels;
- GLint skipRows = packing->SkipRows;
- GLint rowLength;
-
- if (packing->RowLength > 0)
- rowLength = packing->RowLength;
- else
- rowLength = width;
-
- /* horizontal clipping */
- if (srcX < 0) {
- skipPixels -= srcX;
- readWidth += srcX;
- srcX = 0;
- }
- if (srcX + readWidth > (GLint) ctx->ReadBuffer->Width)
- readWidth -= (srcX + readWidth - (GLint) ctx->ReadBuffer->Width);
- if (readWidth <= 0)
- return GL_TRUE;
-
- /* vertical clipping */
- if (srcY < 0) {
- skipRows -= srcY;
- readHeight += srcY;
- srcY = 0;
+ ASSERT(rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB);
+
+ /* clipping should have already been done */
+ ASSERT(x + width <= (GLint) rb->Width);
+ ASSERT(y + height <= (GLint) rb->Height);
+
+ /* check for things we can't handle here */
+ if (transferOps ||
+ packing->SwapBytes ||
+ packing->LsbFirst) {
+ return GL_FALSE;
+ }
+
+ if (format == GL_RGBA && rb->DataType == type) {
+ const GLint dstStride = _mesa_image_row_stride(packing, width,
+ format, type);
+ GLubyte *dest
+ = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
+ format, type, 0, 0);
+ GLint row;
+ ASSERT(rb->GetRow);
+ for (row = 0; row < height; row++) {
+ rb->GetRow(ctx, rb, width, x, y + row, dest);
+ dest += dstStride;
}
- if (srcY + readHeight > (GLint) ctx->ReadBuffer->Height)
- readHeight -= (srcY + readHeight - (GLint) ctx->ReadBuffer->Height);
- if (readHeight <= 0)
- return GL_TRUE;
-
- /*
- * Ready to read!
- * The window region at (destX, destY) of size (readWidth, readHeight)
- * will be read back.
- * We'll write pixel data to buffer pointed to by "pixels" but we'll
- * skip "skipRows" rows and skip "skipPixels" pixels/row.
- */
-#if CHAN_BITS == 8
- if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
-#elif CHAN_BITS == 16
- if (format == GL_RGBA && type == GL_UNSIGNED_SHORT) {
-#else
- if (0) {
-#endif
- GLchan *dest = (GLchan *) pixels
- + (skipRows * rowLength + skipPixels) * 4;
- GLint row;
-
- if (packing->Invert) {
- /* start at top and go down */
- dest += (readHeight - 1) * rowLength * 4;
- rowLength = -rowLength;
- }
+ return GL_TRUE;
+ }
- for (row=0; row<readHeight; row++) {
- (*swrast->Driver.ReadRGBASpan)(ctx, readWidth, srcX, srcY,
- (GLchan (*)[4]) dest);
- if (ctx->DrawBuffer->UseSoftwareAlphaBuffers) {
- _mesa_read_alpha_span(ctx, readWidth, srcX, srcY,
- (GLchan (*)[4]) dest);
- }
- dest += rowLength * 4;
- srcY++;
+ if (format == GL_RGB &&
+ rb->DataType == GL_UNSIGNED_BYTE &&
+ type == GL_UNSIGNED_BYTE) {
+ const GLint dstStride = _mesa_image_row_stride(packing, width,
+ format, type);
+ GLubyte *dest
+ = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
+ format, type, 0, 0);
+ GLint row;
+ ASSERT(rb->GetRow);
+ for (row = 0; row < height; row++) {
+ GLubyte tempRow[MAX_WIDTH][4];
+ GLint col;
+ rb->GetRow(ctx, rb, width, x, y + row, tempRow);
+ /* convert RGBA to RGB */
+ for (col = 0; col < width; col++) {
+ dest[col * 3 + 0] = tempRow[col][0];
+ dest[col * 3 + 1] = tempRow[col][1];
+ dest[col * 3 + 2] = tempRow[col][2];
}
- return GL_TRUE;
- }
- else {
- /* can't do this format/type combination */
- return GL_FALSE;
+ dest += dstStride;
}
+ return GL_TRUE;
+ }
+
+ /* not handled */
+ return GL_FALSE;
+}
+
+
+/**
+ * When we're using a low-precision color buffer (like 16-bit 5/6/5)
+ * we have to adjust our color values a bit to pass conformance.
+ * The problem is when a 5 or 6-bit color value is convert to an 8-bit
+ * value and then a floating point value, the floating point values don't
+ * increment uniformly as the 5 or 6-bit value is incremented.
+ *
+ * This function adjusts floating point values to compensate.
+ */
+static void
+adjust_colors(GLcontext *ctx, GLuint n, GLfloat rgba[][4])
+{
+ const GLuint rShift = 8 - ctx->Visual.redBits;
+ const GLuint gShift = 8 - ctx->Visual.greenBits;
+ const GLuint bShift = 8 - ctx->Visual.blueBits;
+ const GLfloat rScale = 1.0F / (GLfloat) ((1 << ctx->Visual.redBits ) - 1);
+ const GLfloat gScale = 1.0F / (GLfloat) ((1 << ctx->Visual.greenBits) - 1);
+ const GLfloat bScale = 1.0F / (GLfloat) ((1 << ctx->Visual.blueBits ) - 1);
+ GLuint i;
+ for (i = 0; i < n; i++) {
+ GLint r, g, b;
+ /* convert float back to ubyte */
+ CLAMPED_FLOAT_TO_UBYTE(r, rgba[i][RCOMP]);
+ CLAMPED_FLOAT_TO_UBYTE(g, rgba[i][GCOMP]);
+ CLAMPED_FLOAT_TO_UBYTE(b, rgba[i][BCOMP]);
+ /* using only the N most significant bits of the ubyte value, convert to
+ * float in [0,1].
+ */
+ rgba[i][RCOMP] = (GLfloat) (r >> rShift) * rScale;
+ rgba[i][GCOMP] = (GLfloat) (g >> gShift) * gScale;
+ rgba[i][BCOMP] = (GLfloat) (b >> bShift) * bScale;
}
}
const struct gl_pixelstore_attrib *packing )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
- GLint readWidth;
+ GLbitfield transferOps = ctx->_ImageTransferState;
+ struct gl_framebuffer *fb = ctx->ReadBuffer;
+ struct gl_renderbuffer *rb = fb->_ColorReadBuffer;
- _swrast_use_read_buffer(ctx);
+ if (!rb)
+ return;
- /* Try optimized path first */
- if (read_fast_rgba_pixels( ctx, x, y, width, height,
- format, type, pixels, packing )) {
+ if (type == GL_FLOAT && ((ctx->Color.ClampReadColor == GL_TRUE) ||
+ (ctx->Color.ClampReadColor == GL_FIXED_ONLY_ARB &&
+ rb->DataType != GL_FLOAT)))
+ transferOps |= IMAGE_CLAMP_BIT;
- _swrast_use_draw_buffer(ctx);
+ /* Try optimized path first */
+ if (fast_read_rgba_pixels(ctx, x, y, width, height,
+ format, type, pixels, packing, transferOps)) {
return; /* done! */
}
- readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
-
- /* do error checking on pixel type, format was already checked by caller */
- switch (type) {
- case GL_UNSIGNED_BYTE:
- case GL_BYTE:
- case GL_UNSIGNED_SHORT:
- case GL_SHORT:
- case GL_UNSIGNED_INT:
- case GL_INT:
- case GL_FLOAT:
- case GL_UNSIGNED_BYTE_3_3_2:
- case GL_UNSIGNED_BYTE_2_3_3_REV:
- case GL_UNSIGNED_SHORT_5_6_5:
- case GL_UNSIGNED_SHORT_5_6_5_REV:
- case GL_UNSIGNED_SHORT_4_4_4_4:
- case GL_UNSIGNED_SHORT_4_4_4_4_REV:
- case GL_UNSIGNED_SHORT_5_5_5_1:
- case GL_UNSIGNED_SHORT_1_5_5_5_REV:
- case GL_UNSIGNED_INT_8_8_8_8:
- case GL_UNSIGNED_INT_8_8_8_8_REV:
- case GL_UNSIGNED_INT_10_10_10_2:
- case GL_UNSIGNED_INT_2_10_10_10_REV:
- /* valid pixel type */
- break;
- default:
- _mesa_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
- return;
- }
-
- if (!_mesa_is_legal_format_and_type(format, type) ||
- format == GL_INTENSITY) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(format or type)");
- return;
- }
+ /* width should never be > MAX_WIDTH since we did clipping earlier */
+ ASSERT(width <= MAX_WIDTH);
if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
- const GLuint transferOps = ctx->_ImageTransferState;
GLfloat *dest, *src, *tmpImage, *convImage;
GLint row;
- tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
+ tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
if (!tmpImage) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
return;
}
- convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
+ convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
if (!convImage) {
- FREE(tmpImage);
+ _mesa_free(tmpImage);
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
return;
}
/* read full RGBA, FLOAT image */
dest = tmpImage;
for (row = 0; row < height; row++, y++) {
- GLchan rgba[MAX_WIDTH][4];
- if (ctx->Visual.rgbMode) {
- _mesa_read_rgba_span(ctx, ctx->ReadBuffer, readWidth, x, y, rgba);
+ if (fb->Visual.rgbMode) {
+ _swrast_read_rgba_span(ctx, rb, width, x, y, GL_FLOAT, dest);
}
else {
GLuint index[MAX_WIDTH];
- (*swrast->Driver.ReadCI32Span)(ctx, readWidth, x, y, index);
- if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset !=0 ) {
- _mesa_map_ci(ctx, readWidth, index);
- }
- _mesa_map_ci_to_rgba_chan(ctx, readWidth, index, rgba);
+ ASSERT(rb->DataType == GL_UNSIGNED_INT);
+ rb->GetRow(ctx, rb, width, x, y, index);
+ _mesa_apply_ci_transfer_ops(ctx,
+ transferOps & IMAGE_SHIFT_OFFSET_BIT,
+ width, index);
+ _mesa_map_ci_to_rgba(ctx, width, index, (GLfloat (*)[4]) dest);
}
- _mesa_pack_rgba_span(ctx, readWidth, (const GLchan (*)[4]) rgba,
- GL_RGBA, GL_FLOAT, dest, &_mesa_native_packing,
- transferOps & IMAGE_PRE_CONVOLUTION_BITS);
+ _mesa_apply_rgba_transfer_ops(ctx,
+ transferOps & IMAGE_PRE_CONVOLUTION_BITS,
+ width, (GLfloat (*)[4]) dest);
dest += width * 4;
}
/* do convolution */
if (ctx->Pixel.Convolution2DEnabled) {
- _mesa_convolve_2d_image(ctx, &readWidth, &height, tmpImage, convImage);
+ _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
}
else {
ASSERT(ctx->Pixel.Separable2DEnabled);
- _mesa_convolve_sep_image(ctx, &readWidth, &height, tmpImage, convImage);
+ _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
}
- FREE(tmpImage);
+ _mesa_free(tmpImage);
/* finish transfer ops and pack the resulting image */
src = convImage;
for (row = 0; row < height; row++) {
GLvoid *dest;
- dest = _mesa_image_address(packing, pixels, readWidth, height,
- format, type, 0, row, 0);
- _mesa_pack_float_rgba_span(ctx, readWidth,
- (const GLfloat (*)[4]) src,
+ dest = _mesa_image_address2d(packing, pixels, width, height,
+ format, type, row, 0);
+ _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) src,
format, type, dest, packing,
transferOps & IMAGE_POST_CONVOLUTION_BITS);
- src += readWidth * 4;
+ src += width * 4;
}
+ _mesa_free(convImage);
}
else {
/* no convolution */
+ const GLint dstStride
+ = _mesa_image_row_stride(packing, width, format, type);
+ GLfloat (*rgba)[4] = swrast->SpanArrays->attribs[FRAG_ATTRIB_COL0];
GLint row;
+ GLubyte *dst
+ = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
+ format, type, 0, 0);
+
+ /* make sure we don't apply 1D convolution */
+ transferOps &= ~(IMAGE_CONVOLUTION_BIT |
+ IMAGE_POST_CONVOLUTION_SCALE_BIAS);
+
for (row = 0; row < height; row++, y++) {
- GLchan rgba[MAX_WIDTH][4];
- GLvoid *dst;
- if (ctx->Visual.rgbMode) {
- _mesa_read_rgba_span(ctx, ctx->ReadBuffer, readWidth, x, y, rgba);
+
+ /* Get float rgba pixels */
+ if (fb->Visual.rgbMode) {
+ _swrast_read_rgba_span(ctx, rb, width, x, y, GL_FLOAT, rgba);
}
else {
+ /* read CI and convert to RGBA */
GLuint index[MAX_WIDTH];
- (*swrast->Driver.ReadCI32Span)(ctx, readWidth, x, y, index);
- if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset != 0) {
- _mesa_map_ci(ctx, readWidth, index);
- }
- _mesa_map_ci_to_rgba_chan(ctx, readWidth, index, rgba);
+ ASSERT(rb->DataType == GL_UNSIGNED_INT);
+ rb->GetRow(ctx, rb, width, x, y, index);
+ _mesa_apply_ci_transfer_ops(ctx,
+ transferOps & IMAGE_SHIFT_OFFSET_BIT,
+ width, index);
+ _mesa_map_ci_to_rgba(ctx, width, index, rgba);
}
- dst = _mesa_image_address(packing, pixels, width, height,
- format, type, 0, row, 0);
- if (ctx->Visual.redBits < CHAN_BITS ||
- ctx->Visual.greenBits < CHAN_BITS ||
- ctx->Visual.blueBits < CHAN_BITS) {
- /* Requantize the color values into floating point and go from
- * there. This fixes conformance failures with 16-bit color
- * buffers, for example.
- */
- DEFMARRAY(GLfloat, rgbaf, MAX_WIDTH, 4); /* mac 32k limitation */
- CHECKARRAY(rgbaf, return); /* mac 32k limitation */
- _mesa_chan_to_float_span(ctx, readWidth,
- (CONST GLchan (*)[4]) rgba, rgbaf);
- _mesa_pack_float_rgba_span(ctx, readWidth,
- (CONST GLfloat (*)[4]) rgbaf,
- format, type, dst, packing,
- ctx->_ImageTransferState);
- UNDEFARRAY(rgbaf); /* mac 32k limitation */
+
+ /* apply fudge factor for shallow color buffers */
+ if (fb->Visual.redBits < 8 ||
+ fb->Visual.greenBits < 8 ||
+ fb->Visual.blueBits < 8) {
+ adjust_colors(ctx, width, rgba);
+ }
+
+ /* pack the row of RGBA pixels into user's buffer */
+ _mesa_pack_rgba_span_float(ctx, width, rgba, format, type, dst,
+ packing, transferOps);
+
+ dst += dstStride;
+ }
+ }
+}
+
+
+/**
+ * Read combined depth/stencil values.
+ * We'll have already done error checking to be sure the expected
+ * depth and stencil buffers really exist.
+ */
+static void
+read_depth_stencil_pixels(GLcontext *ctx,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum type, GLvoid *pixels,
+ const struct gl_pixelstore_attrib *packing )
+{
+ const GLboolean scaleOrBias
+ = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
+ const GLboolean stencilTransfer = ctx->Pixel.IndexShift
+ || ctx->Pixel.IndexOffset || ctx->Pixel.MapStencilFlag;
+ struct gl_renderbuffer *depthRb, *stencilRb;
+
+ depthRb = ctx->ReadBuffer->_DepthBuffer;
+ stencilRb = ctx->ReadBuffer->_StencilBuffer;
+
+ if (!depthRb || !stencilRb)
+ return;
+
+ depthRb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
+ stencilRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
+
+ if (depthRb->_BaseFormat == GL_DEPTH_STENCIL_EXT &&
+ stencilRb->_BaseFormat == GL_DEPTH_STENCIL_EXT &&
+ depthRb == stencilRb &&
+ !scaleOrBias &&
+ !stencilTransfer) {
+ /* This is the ideal case.
+ * Reading GL_DEPTH_STENCIL pixels from combined depth/stencil buffer.
+ * Plus, no pixel transfer ops to worry about!
+ */
+ GLint i;
+ GLint dstStride = _mesa_image_row_stride(packing, width,
+ GL_DEPTH_STENCIL_EXT, type);
+ GLubyte *dst = (GLubyte *) _mesa_image_address2d(packing, pixels,
+ width, height,
+ GL_DEPTH_STENCIL_EXT,
+ type, 0, 0);
+ for (i = 0; i < height; i++) {
+ depthRb->GetRow(ctx, depthRb, width, x, y + i, dst);
+ dst += dstStride;
+ }
+ }
+ else {
+ /* Reading GL_DEPTH_STENCIL pixels from separate depth/stencil buffers,
+ * or we need pixel transfer.
+ */
+ GLint i;
+ depthRb = ctx->ReadBuffer->_DepthBuffer;
+ stencilRb = ctx->ReadBuffer->_StencilBuffer;
+
+ for (i = 0; i < height; i++) {
+ GLstencil stencilVals[MAX_WIDTH];
+
+ GLuint *depthStencilDst = (GLuint *)
+ _mesa_image_address2d(packing, pixels, width, height,
+ GL_DEPTH_STENCIL_EXT, type, i, 0);
+
+ _swrast_read_stencil_span(ctx, stencilRb, width,
+ x, y + i, stencilVals);
+
+ if (!scaleOrBias && !stencilTransfer
+ && ctx->ReadBuffer->Visual.depthBits == 24) {
+ /* ideal case */
+ GLuint zVals[MAX_WIDTH]; /* 24-bit values! */
+ GLint j;
+ ASSERT(depthRb->DataType == GL_UNSIGNED_INT);
+ /* note, we've already been clipped */
+ depthRb->GetRow(ctx, depthRb, width, x, y + i, zVals);
+ for (j = 0; j < width; j++) {
+ depthStencilDst[j] = (zVals[j] << 8) | (stencilVals[j] & 0xff);
+ }
}
else {
- /* GLubytes are fine */
- _mesa_pack_rgba_span(ctx, readWidth, (CONST GLchan (*)[4]) rgba,
- format, type, dst, packing,
- ctx->_ImageTransferState);
+ /* general case */
+ GLfloat depthVals[MAX_WIDTH];
+ _swrast_read_depth_span_float(ctx, depthRb, width, x, y + i,
+ depthVals);
+ _mesa_pack_depth_stencil_span(ctx, width, depthStencilDst,
+ depthVals, stencilVals, packing);
}
}
}
-
- _swrast_use_draw_buffer(ctx);
}
+/**
+ * Software fallback routine for ctx->Driver.ReadPixels().
+ * By time we get here, all error checking will have been done.
+ */
void
_swrast_ReadPixels( GLcontext *ctx,
GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type,
- const struct gl_pixelstore_attrib *pack,
+ const struct gl_pixelstore_attrib *packing,
GLvoid *pixels )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
- (void) pack;
+ struct gl_pixelstore_attrib clippedPacking = *packing;
+
+ /* Need to do RENDER_START before clipping or anything else since this
+ * is where a driver may grab the hw lock and get an updated window
+ * size.
+ */
+ RENDER_START(swrast, ctx);
+
+ if (ctx->NewState)
+ _mesa_update_state(ctx);
if (swrast->NewState)
_swrast_validate_derived( ctx );
- RENDER_START(swrast,ctx);
+ /* Do all needed clipping here, so that we can forget about it later */
+ if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) {
+ /* The ReadPixels region is totally outside the window bounds */
+ RENDER_FINISH(swrast, ctx);
+ return;
+ }
+ pixels = _mesa_map_readpix_pbo(ctx, &clippedPacking, pixels);
+ if (!pixels)
+ return;
+
switch (format) {
case GL_COLOR_INDEX:
- read_index_pixels(ctx, x, y, width, height, type, pixels, &ctx->Pack);
+ read_index_pixels(ctx, x, y, width, height, type, pixels,
+ &clippedPacking);
break;
case GL_STENCIL_INDEX:
- read_stencil_pixels(ctx, x,y, width,height, type, pixels, &ctx->Pack);
+ read_stencil_pixels(ctx, x, y, width, height, type, pixels,
+ &clippedPacking);
break;
case GL_DEPTH_COMPONENT:
- read_depth_pixels(ctx, x, y, width, height, type, pixels, &ctx->Pack);
+ read_depth_pixels(ctx, x, y, width, height, type, pixels,
+ &clippedPacking);
break;
case GL_RED:
case GL_GREEN:
case GL_BGRA:
case GL_ABGR_EXT:
read_rgba_pixels(ctx, x, y, width, height,
- format, type, pixels, &ctx->Pack);
+ format, type, pixels, &clippedPacking);
break;
+ case GL_DEPTH_STENCIL_EXT:
+ read_depth_stencil_pixels(ctx, x, y, width, height,
+ type, pixels, &clippedPacking);
+ break;
default:
- _mesa_error( ctx, GL_INVALID_ENUM, "glReadPixels(format)" );
+ _mesa_problem(ctx, "unexpected format in _swrast_ReadPixels");
+ /* don't return yet, clean-up */
}
- RENDER_FINISH(swrast,ctx);
+ RENDER_FINISH(swrast, ctx);
+
+ _mesa_unmap_readpix_pbo(ctx, &clippedPacking);
}